summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2024-11-02 20:55:56 +0800
committerErik Kundiman <erik@megapahit.org>2024-11-03 19:33:18 +0800
commit3f72f9a202bed628f838cc24fe58a0511ca0d161 (patch)
tree0684cfff91551d9b6aabdb825981b46a5cb53fe8 /indra/newview
parentd302bf3c96666cfd46d7585cb3d8b6ec27bb83bf (diff)
parent9c0a6d1b0e5e9d6da6a63ff367f40ab08c064bbe (diff)
Merge remote-tracking branch 'secondlife/release/maint-c' into maint-c
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt69
-rw-r--r--indra/newview/FixBundle.cmake.in6
-rw-r--r--indra/newview/FixPackage.cmake.in6
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rw-r--r--indra/newview/app_settings/cmd_line.xml28
-rw-r--r--indra/newview/app_settings/gamecontrollerdb.txt2043
-rw-r--r--indra/newview/app_settings/settings.xml973
-rw-r--r--indra/newview/app_settings/settings_per_account.xml2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl1
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/cofF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl44
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl39
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl6
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl1
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl3
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl1
-rw-r--r--indra/newview/featuretable_linux.txt607
-rw-r--r--indra/newview/gltfscenemanager.cpp5
-rw-r--r--indra/newview/groupchatlistener.cpp97
-rw-r--r--indra/newview/groupchatlistener.h23
-rwxr-xr-xindra/newview/linux_tools/wrapper.sh23
-rw-r--r--indra/newview/llagent.cpp373
-rw-r--r--indra/newview/llagent.h37
-rw-r--r--indra/newview/llagentcamera.cpp30
-rw-r--r--indra/newview/llagentcamera.h9
-rw-r--r--indra/newview/llagentlistener.cpp435
-rw-r--r--indra/newview/llagentlistener.h20
-rw-r--r--indra/newview/llagentpilot.cpp4
-rw-r--r--indra/newview/llaisapi.cpp2
-rw-r--r--indra/newview/llappearancelistener.cpp146
-rw-r--r--indra/newview/llappearancelistener.h46
-rw-r--r--indra/newview/llappearancemgr.cpp89
-rw-r--r--indra/newview/llappearancemgr.h10
-rw-r--r--indra/newview/llappviewer.cpp310
-rw-r--r--indra/newview/llappviewer.h6
-rw-r--r--indra/newview/llappviewerlinux.cpp21
-rw-r--r--indra/newview/llappviewerlistener.cpp20
-rw-r--r--indra/newview/llappviewerlistener.h5
-rw-r--r--indra/newview/llautoreplace.cpp5
-rw-r--r--indra/newview/llavataractions.cpp23
-rw-r--r--indra/newview/llavataractions.h9
-rw-r--r--indra/newview/llblocklist.cpp2
-rw-r--r--indra/newview/llcallbacklist.cpp305
-rw-r--r--indra/newview/llchathistory.cpp45
-rw-r--r--indra/newview/llchathistory.h3
-rw-r--r--indra/newview/llchatitemscontainerctrl.cpp5
-rw-r--r--indra/newview/llchatitemscontainerctrl.h6
-rw-r--r--indra/newview/llchiclet.cpp12
-rw-r--r--indra/newview/llcofwearables.cpp10
-rw-r--r--indra/newview/llcontrolavatar.cpp16
-rw-r--r--indra/newview/llconversationlog.cpp20
-rw-r--r--indra/newview/llconversationloglist.cpp5
-rw-r--r--indra/newview/llconversationmodel.h3
-rw-r--r--indra/newview/llcylinder.cpp2
-rw-r--r--indra/newview/lldirpicker.cpp37
-rw-r--r--indra/newview/lldirpicker.h2
-rw-r--r--indra/newview/lldonotdisturbnotificationstorage.h2
-rw-r--r--indra/newview/lldrawpoolalpha.cpp9
-rw-r--r--indra/newview/lldrawpoolbump.cpp7
-rw-r--r--indra/newview/lldrawpoolterrain.cpp8
-rw-r--r--indra/newview/lldrawpoolwlsky.cpp1
-rw-r--r--indra/newview/llenvironment.cpp56
-rw-r--r--indra/newview/llenvironment.h4
-rw-r--r--indra/newview/llexpandabletextbox.cpp18
-rw-r--r--indra/newview/llfavoritesbar.cpp2
-rw-r--r--indra/newview/llfeaturemanager.cpp29
-rw-r--r--indra/newview/llfilepicker.cpp641
-rw-r--r--indra/newview/llfilepicker.h9
-rw-r--r--indra/newview/llfloater360capture.cpp11
-rw-r--r--indra/newview/llfloaterauction.cpp8
-rw-r--r--indra/newview/llfloaterautoreplacesettings.cpp51
-rw-r--r--indra/newview/llfloaterautoreplacesettings.h2
-rw-r--r--indra/newview/llfloateravatarpicker.cpp2
-rw-r--r--indra/newview/llfloateravatarrendersettings.cpp4
-rw-r--r--indra/newview/llfloaterbeacons.cpp2
-rw-r--r--indra/newview/llfloaterbulkpermission.cpp12
-rw-r--r--indra/newview/llfloaterbulkupload.cpp4
-rw-r--r--indra/newview/llfloaterbulkupload.h1
-rw-r--r--indra/newview/llfloaterbump.cpp25
-rw-r--r--indra/newview/llfloaterbump.h1
-rw-r--r--indra/newview/llfloaterbvhpreview.cpp7
-rw-r--r--indra/newview/llfloaterbvhpreview.h2
-rw-r--r--indra/newview/llfloatercamera.cpp16
-rw-r--r--indra/newview/llfloatercamerapresets.cpp4
-rw-r--r--indra/newview/llfloaterconversationlog.cpp2
-rw-r--r--indra/newview/llfloatereditenvironmentbase.h3
-rw-r--r--indra/newview/llfloatereditextdaycycle.cpp4
-rw-r--r--indra/newview/llfloatergesture.cpp10
-rw-r--r--indra/newview/llfloatergltfasseteditor.cpp4
-rw-r--r--indra/newview/llfloatergodtools.cpp41
-rw-r--r--indra/newview/llfloaterimagepreview.cpp4
-rw-r--r--indra/newview/llfloaterimagepreview.h2
-rw-r--r--indra/newview/llfloaterimcontainer.cpp16
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp5
-rw-r--r--indra/newview/llfloaterimnearbychathandler.cpp13
-rw-r--r--indra/newview/llfloaterimnearbychatlistener.cpp35
-rw-r--r--indra/newview/llfloaterimnearbychatlistener.h6
-rw-r--r--indra/newview/llfloaterimsession.cpp2
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp63
-rw-r--r--indra/newview/llfloaterimsessiontab.h5
-rw-r--r--indra/newview/llfloaterinspect.cpp9
-rw-r--r--indra/newview/llfloaterinventorysettings.cpp27
-rw-r--r--indra/newview/llfloaterinventorysettings.h5
-rw-r--r--indra/newview/llfloaterjoystick.cpp33
-rw-r--r--indra/newview/llfloaterlagmeter.cpp2
-rw-r--r--indra/newview/llfloaterland.cpp3
-rw-r--r--indra/newview/llfloaterlinkreplace.cpp8
-rw-r--r--indra/newview/llfloaterlinkreplace.h6
-rw-r--r--indra/newview/llfloaterluadebug.cpp170
-rw-r--r--indra/newview/llfloaterluadebug.h72
-rw-r--r--indra/newview/llfloaterluascripts.cpp137
-rw-r--r--indra/newview/llfloaterluascripts.h54
-rw-r--r--indra/newview/llfloatermarketplacelistings.cpp2
-rw-r--r--indra/newview/llfloatermemleak.cpp12
-rw-r--r--indra/newview/llfloatermodelpreview.cpp16
-rw-r--r--indra/newview/llfloatermodelpreview.h7
-rw-r--r--indra/newview/llfloatermyenvironment.cpp121
-rw-r--r--indra/newview/llfloatermyenvironment.h3
-rw-r--r--indra/newview/llfloaternamedesc.cpp32
-rw-r--r--indra/newview/llfloaternamedesc.h9
-rw-r--r--indra/newview/llfloaternotificationsconsole.cpp2
-rw-r--r--indra/newview/llfloaterobjectweights.cpp96
-rw-r--r--indra/newview/llfloaterobjectweights.h19
-rw-r--r--indra/newview/llfloateropenobject.cpp4
-rw-r--r--indra/newview/llfloaterperformance.cpp2
-rw-r--r--indra/newview/llfloaterperms.cpp6
-rw-r--r--indra/newview/llfloaterpostprocess.cpp229
-rw-r--r--indra/newview/llfloaterpostprocess.h72
-rw-r--r--indra/newview/llfloaterpreference.cpp1340
-rw-r--r--indra/newview/llfloaterpreference.h182
-rw-r--r--indra/newview/llfloaterpreferencesgraphicsadvanced.cpp10
-rw-r--r--indra/newview/llfloaterpreferenceviewadvanced.cpp2
-rw-r--r--indra/newview/llfloaterregioninfo.cpp196
-rw-r--r--indra/newview/llfloaterregioninfo.h32
-rw-r--r--indra/newview/llfloaterregionrestarting.h8
-rw-r--r--indra/newview/llfloaterscriptedprefs.cpp4
-rw-r--r--indra/newview/llfloatersettingscolor.cpp4
-rw-r--r--indra/newview/llfloatersettingsdebug.cpp29
-rw-r--r--indra/newview/llfloatersettingsdebug.h3
-rw-r--r--indra/newview/llfloatertestinspectors.cpp4
-rw-r--r--indra/newview/llfloatertools.cpp30
-rw-r--r--indra/newview/llfloatertopobjects.cpp20
-rw-r--r--indra/newview/llfloatertoybox.cpp4
-rw-r--r--indra/newview/llfloateruipreview.cpp2
-rw-r--r--indra/newview/llfloatervoiceeffect.cpp6
-rw-r--r--indra/newview/llfloaterwebcontent.cpp14
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp29
-rw-r--r--indra/newview/llflycam.cpp136
-rw-r--r--indra/newview/llflycam.h60
-rw-r--r--indra/newview/llflyoutcombobtn.cpp2
-rw-r--r--indra/newview/llfolderviewmodelinventory.cpp30
-rw-r--r--indra/newview/llfolderviewmodelinventory.h1
-rw-r--r--indra/newview/llgltffolderitem.h5
-rw-r--r--indra/newview/llgltfmateriallist.cpp9
-rw-r--r--indra/newview/llgroupactions.cpp8
-rw-r--r--indra/newview/llgrouplist.cpp2
-rw-r--r--indra/newview/llhudeffectresetskeleton.cpp211
-rw-r--r--indra/newview/llhudeffectresetskeleton.h59
-rw-r--r--indra/newview/llhudnametag.cpp37
-rw-r--r--indra/newview/llhudnametag.h3
-rw-r--r--indra/newview/llhudobject.cpp4
-rw-r--r--indra/newview/llhudobject.h3
-rw-r--r--indra/newview/llhudrender.cpp16
-rw-r--r--indra/newview/llhudrender.h2
-rw-r--r--indra/newview/llhudtext.cpp16
-rw-r--r--indra/newview/llhudtext.h2
-rw-r--r--indra/newview/llimprocessing.cpp49
-rw-r--r--indra/newview/llimprocessing.h1
-rw-r--r--indra/newview/llimview.cpp17
-rw-r--r--indra/newview/llimview.h6
-rw-r--r--indra/newview/llinspectgroup.cpp6
-rw-r--r--indra/newview/llinspectobject.cpp16
-rw-r--r--indra/newview/llinspecttexture.cpp19
-rw-r--r--indra/newview/llinventorybridge.cpp147
-rw-r--r--indra/newview/llinventorybridge.h45
-rw-r--r--indra/newview/llinventoryfilter.cpp85
-rw-r--r--indra/newview/llinventoryfilter.h17
-rw-r--r--indra/newview/llinventoryfunctions.cpp239
-rw-r--r--indra/newview/llinventoryfunctions.h36
-rw-r--r--indra/newview/llinventorygallery.cpp59
-rw-r--r--indra/newview/llinventorygallery.h5
-rw-r--r--indra/newview/llinventorygallerymenu.cpp118
-rw-r--r--indra/newview/llinventoryitemslist.cpp2
-rw-r--r--indra/newview/llinventorylistener.cpp394
-rw-r--r--indra/newview/llinventorylistener.h53
-rw-r--r--indra/newview/llinventorymodel.cpp24
-rw-r--r--indra/newview/llinventoryobserver.cpp29
-rw-r--r--indra/newview/llinventoryobserver.h19
-rw-r--r--indra/newview/llinventorypanel.cpp373
-rw-r--r--indra/newview/llinventorypanel.h7
-rw-r--r--indra/newview/llkeyconflict.cpp21
-rw-r--r--indra/newview/llkeyconflict.h12
-rw-r--r--indra/newview/lllocalbitmaps.cpp11
-rw-r--r--indra/newview/lllocalbitmaps.h3
-rw-r--r--indra/newview/lllocalgltfmaterials.cpp9
-rw-r--r--indra/newview/lllocalgltfmaterials.h3
-rw-r--r--indra/newview/lllocationinputctrl.cpp2
-rw-r--r--indra/newview/lllogchat.cpp48
-rw-r--r--indra/newview/llluamanager.cpp484
-rw-r--r--indra/newview/llluamanager.h133
-rw-r--r--indra/newview/llmanip.cpp10
-rw-r--r--indra/newview/llmaniprotate.cpp4
-rw-r--r--indra/newview/llmanipscale.cpp4
-rw-r--r--indra/newview/llmaniptranslate.cpp4
-rw-r--r--indra/newview/llmaterialeditor.cpp35
-rw-r--r--indra/newview/llmaterialeditor.h14
-rw-r--r--indra/newview/llmediactrl.cpp4
-rw-r--r--indra/newview/llmediadataclient.h4
-rw-r--r--indra/newview/llmeshrepository.cpp122
-rw-r--r--indra/newview/llmeshrepository.h20
-rw-r--r--indra/newview/llmodelpreview.cpp3
-rw-r--r--indra/newview/llnetmap.cpp2
-rw-r--r--indra/newview/llnotificationlistitem.cpp21
-rw-r--r--indra/newview/lloutfitgallery.cpp210
-rw-r--r--indra/newview/lloutfitgallery.h36
-rw-r--r--indra/newview/lloutfitslist.cpp353
-rw-r--r--indra/newview/lloutfitslist.h63
-rw-r--r--indra/newview/llpanelappearancetab.h7
-rw-r--r--indra/newview/llpanelblockedlist.cpp2
-rw-r--r--indra/newview/llpaneleditsky.cpp8
-rw-r--r--indra/newview/llpaneleditwearable.cpp4
-rw-r--r--indra/newview/llpanelemojicomplete.cpp9
-rw-r--r--indra/newview/llpanelenvironment.cpp23
-rw-r--r--indra/newview/llpanelface.cpp6
-rw-r--r--indra/newview/llpanelgroupbulk.cpp32
-rw-r--r--indra/newview/llpanelgroupbulkban.cpp33
-rw-r--r--indra/newview/llpanelgroupbulkimpl.h3
-rw-r--r--indra/newview/llpanelgroupcreate.cpp1
-rw-r--r--indra/newview/llpanelgroupgeneral.cpp1
-rw-r--r--indra/newview/llpanellandmarkinfo.cpp4
-rw-r--r--indra/newview/llpanellandmarks.cpp8
-rw-r--r--indra/newview/llpanellogin.cpp57
-rw-r--r--indra/newview/llpanellogin.h2
-rw-r--r--indra/newview/llpanelloginlistener.cpp196
-rw-r--r--indra/newview/llpanelloginlistener.h2
-rw-r--r--indra/newview/llpanelmaininventory.cpp280
-rw-r--r--indra/newview/llpanelmediasettingssecurity.cpp4
-rw-r--r--indra/newview/llpanelnearbymedia.cpp26
-rw-r--r--indra/newview/llpanelobject.cpp2
-rw-r--r--indra/newview/llpanelobjectinventory.cpp68
-rw-r--r--indra/newview/llpaneloutfitedit.cpp10
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp67
-rw-r--r--indra/newview/llpaneloutfitsinventory.h22
-rw-r--r--indra/newview/llpanelpeople.cpp47
-rw-r--r--indra/newview/llpanelpeoplemenus.cpp27
-rw-r--r--indra/newview/llpanelpermissions.cpp16
-rw-r--r--indra/newview/llpanelpermissions.h1
-rw-r--r--indra/newview/llpanelplaces.cpp2
-rw-r--r--indra/newview/llpanelpresetscamerapulldown.cpp4
-rw-r--r--indra/newview/llpanelpresetspulldown.cpp6
-rw-r--r--indra/newview/llpanelprimmediacontrols.cpp46
-rw-r--r--indra/newview/llpanelprofile.cpp19
-rw-r--r--indra/newview/llpanelprofile.h7
-rw-r--r--indra/newview/llpanelprofileclassifieds.h16
-rw-r--r--indra/newview/llpanelprofilepicks.cpp42
-rw-r--r--indra/newview/llpanelprofilepicks.h10
-rw-r--r--indra/newview/llpanelsnapshot.cpp12
-rw-r--r--indra/newview/llpanelsnapshotinventory.cpp132
-rw-r--r--indra/newview/llpanelsnapshotlocal.cpp22
-rw-r--r--indra/newview/llpanelsnapshotoptions.cpp45
-rw-r--r--indra/newview/llpanelsnapshotpostcard.cpp24
-rw-r--r--indra/newview/llpanelsnapshotprofile.cpp22
-rw-r--r--indra/newview/llpanelteleporthistory.cpp24
-rw-r--r--indra/newview/llpaneltopinfobar.cpp2
-rw-r--r--indra/newview/llpanelvoicedevicesettings.cpp83
-rw-r--r--indra/newview/llpanelvoicedevicesettings.h1
-rw-r--r--indra/newview/llpanelvoiceeffect.cpp2
-rw-r--r--indra/newview/llpanelvolume.cpp2
-rw-r--r--indra/newview/llpanelvolumepulldown.cpp8
-rw-r--r--indra/newview/llpanelwearing.cpp40
-rw-r--r--indra/newview/llpanelwearing.h6
-rw-r--r--indra/newview/llpreviewanim.cpp2
-rw-r--r--indra/newview/llpreviewscript.cpp7
-rw-r--r--indra/newview/llpreviewscript.h5
-rw-r--r--indra/newview/llreflectionmap.cpp2
-rw-r--r--indra/newview/llsaveoutfitcombobtn.cpp2
-rw-r--r--indra/newview/llsecapi.h2
-rw-r--r--indra/newview/llselectmgr.cpp18
-rw-r--r--indra/newview/llselectmgr.h1
-rw-r--r--indra/newview/llsetkeybinddialog.cpp6
-rw-r--r--indra/newview/llsidepanelappearance.cpp9
-rw-r--r--indra/newview/llsidepaneliteminfo.cpp32
-rw-r--r--indra/newview/llsidepaneliteminfo.h2
-rw-r--r--indra/newview/llskinningutil.cpp4
-rw-r--r--indra/newview/llsky.cpp2
-rw-r--r--indra/newview/llsky.h1
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp2
-rw-r--r--indra/newview/llspeakers.h4
-rw-r--r--indra/newview/llsprite.cpp2
-rw-r--r--indra/newview/llsprite.h2
-rw-r--r--indra/newview/llstartup.cpp10
-rw-r--r--indra/newview/llsurface.h1
-rw-r--r--indra/newview/llteleporthistorystorage.cpp6
-rw-r--r--indra/newview/llterrainpaintmap.cpp712
-rw-r--r--indra/newview/llterrainpaintmap.h128
-rw-r--r--indra/newview/lltexturectrl.cpp79
-rw-r--r--indra/newview/lltexturectrl.h4
-rw-r--r--indra/newview/lltexturefetch.cpp21
-rw-r--r--indra/newview/lltexturefetch.h7
-rw-r--r--indra/newview/llthumbnailctrl.cpp10
-rw-r--r--indra/newview/lltoast.cpp32
-rw-r--r--indra/newview/lltoast.h6
-rw-r--r--indra/newview/lltoastgroupnotifypanel.cpp19
-rw-r--r--indra/newview/lltoastimpanel.cpp5
-rw-r--r--indra/newview/lltooldraganddrop.cpp4
-rw-r--r--indra/newview/lltoolmgr.cpp4
-rw-r--r--indra/newview/lltoolplacer.cpp8
-rw-r--r--indra/newview/lltoolplacer.h4
-rw-r--r--indra/newview/lltoolselect.cpp9
-rw-r--r--indra/newview/lluilistener.cpp368
-rw-r--r--indra/newview/lluilistener.h23
-rw-r--r--indra/newview/llurldispatcher.cpp11
-rw-r--r--indra/newview/llviewerassetupload.cpp38
-rw-r--r--indra/newview/llviewerassetupload.h5
-rw-r--r--indra/newview/llviewerattachmenu.cpp4
-rw-r--r--indra/newview/llviewercamera.cpp83
-rw-r--r--indra/newview/llviewercamera.h24
-rw-r--r--indra/newview/llviewerchat.cpp9
-rw-r--r--indra/newview/llviewercontrol.cpp4
-rw-r--r--indra/newview/llviewercontrollistener.cpp7
-rw-r--r--indra/newview/llviewerdisplay.cpp72
-rw-r--r--indra/newview/llviewerdisplay.h2
-rw-r--r--indra/newview/llviewerfloaterreg.cpp9
-rw-r--r--indra/newview/llviewerinput.cpp50
-rw-r--r--indra/newview/llviewerinventory.cpp10
-rw-r--r--indra/newview/llviewerinventory.h2
-rw-r--r--indra/newview/llviewerjoystick.cpp57
-rw-r--r--indra/newview/llviewerjoystick.h18
-rw-r--r--indra/newview/llviewermedia.cpp7
-rw-r--r--indra/newview/llviewermenu.cpp633
-rw-r--r--indra/newview/llviewermenu.h1
-rw-r--r--indra/newview/llviewermenufile.cpp64
-rw-r--r--indra/newview/llviewermenufile.h15
-rw-r--r--indra/newview/llviewermessage.cpp95
-rw-r--r--indra/newview/llviewerobject.cpp9
-rw-r--r--indra/newview/llviewerobjectlist.cpp5
-rw-r--r--indra/newview/llviewerparcelmediaautoplay.h2
-rwxr-xr-xindra/newview/llviewerparceloverlay.cpp302
-rw-r--r--indra/newview/llviewerparceloverlay.h18
-rwxr-xr-xindra/newview/llviewerregion.cpp5
-rw-r--r--indra/newview/llviewershadermgr.cpp38
-rw-r--r--indra/newview/llviewershadermgr.h1
-rw-r--r--indra/newview/llviewerstats.cpp26
-rw-r--r--indra/newview/llviewerstats.h1
-rw-r--r--indra/newview/llviewertexture.cpp43
-rw-r--r--indra/newview/llviewertexture.h1
-rw-r--r--indra/newview/llviewertexturelist.cpp112
-rw-r--r--indra/newview/llviewertexturelist.h11
-rw-r--r--indra/newview/llviewerwindow.cpp82
-rw-r--r--indra/newview/llviewerwindowlistener.cpp60
-rw-r--r--indra/newview/llvlcomposition.cpp4
-rw-r--r--indra/newview/llvlcomposition.h16
-rw-r--r--indra/newview/llvoavatar.cpp168
-rw-r--r--indra/newview/llvoavatar.h19
-rw-r--r--indra/newview/llvoicecallhandler.cpp5
-rw-r--r--indra/newview/llvoicechannel.cpp6
-rw-r--r--indra/newview/llvoiceclient.cpp11
-rw-r--r--indra/newview/llvoiceclient.h5
-rw-r--r--indra/newview/llvoicevivox.cpp9
-rw-r--r--indra/newview/llvoicevivox.h3
-rw-r--r--indra/newview/llvoicewebrtc.cpp254
-rw-r--r--indra/newview/llvoicewebrtc.h17
-rw-r--r--indra/newview/llvovolume.cpp31
-rw-r--r--indra/newview/llvovolume.h1
-rw-r--r--indra/newview/llwatchdog.cpp35
-rw-r--r--indra/newview/llwatchdog.h12
-rw-r--r--indra/newview/llwearableitemslist.cpp27
-rw-r--r--indra/newview/llwearableitemslist.h8
-rw-r--r--indra/newview/llwindowlistener.cpp2
-rw-r--r--indra/newview/llworldmap.cpp19
-rwxr-xr-xindra/newview/llworldmapview.cpp40
-rw-r--r--indra/newview/llworldmipmap.cpp2
-rw-r--r--indra/newview/llxmlrpctransaction.cpp2
-rw-r--r--indra/newview/pipeline.cpp187
-rw-r--r--indra/newview/pipeline.h4
-rw-r--r--indra/newview/rlvactions.cpp42
-rw-r--r--indra/newview/rlvactions.h46
-rw-r--r--indra/newview/rlvcommon.cpp134
-rw-r--r--indra/newview/rlvcommon.h72
-rw-r--r--indra/newview/rlvdefines.h194
-rw-r--r--indra/newview/rlvfloaters.cpp122
-rw-r--r--indra/newview/rlvfloaters.h68
-rw-r--r--indra/newview/rlvhandler.cpp225
-rw-r--r--indra/newview/rlvhandler.h80
-rw-r--r--indra/newview/rlvhelper.cpp389
-rw-r--r--indra/newview/rlvhelper.h299
-rw-r--r--indra/newview/scripts/lua/frame_profile.lua24
-rw-r--r--indra/newview/scripts/lua/frame_profile_quit.lua34
-rw-r--r--indra/newview/scripts/lua/luafloater_camera_control.xml244
-rw-r--r--indra/newview/scripts/lua/luafloater_demo.xml93
-rw-r--r--indra/newview/scripts/lua/luafloater_gesture_list.xml21
-rw-r--r--indra/newview/scripts/lua/luafloater_outfits_list.xml51
-rw-r--r--indra/newview/scripts/lua/luafloater_speedometer.xml35
-rw-r--r--indra/newview/scripts/lua/qtest.lua146
-rw-r--r--indra/newview/scripts/lua/require/ErrorQueue.lua37
-rw-r--r--indra/newview/scripts/lua/require/LLAgent.lua188
-rw-r--r--indra/newview/scripts/lua/require/LLAppearance.lua31
-rw-r--r--indra/newview/scripts/lua/require/LLChat.lua39
-rw-r--r--indra/newview/scripts/lua/require/LLDebugSettings.lua17
-rw-r--r--indra/newview/scripts/lua/require/LLFloaterAbout.lua11
-rw-r--r--indra/newview/scripts/lua/require/LLGesture.lua23
-rw-r--r--indra/newview/scripts/lua/require/LLInventory.lua67
-rw-r--r--indra/newview/scripts/lua/require/LLListener.lua50
-rw-r--r--indra/newview/scripts/lua/require/Queue.lua51
-rw-r--r--indra/newview/scripts/lua/require/Region.lua17
-rw-r--r--indra/newview/scripts/lua/require/UI.lua245
-rw-r--r--indra/newview/scripts/lua/require/UI/Floater.lua146
-rw-r--r--indra/newview/scripts/lua/require/UI/popup.lua82
-rw-r--r--indra/newview/scripts/lua/require/WaitQueue.lua88
-rw-r--r--indra/newview/scripts/lua/require/coro.lua67
-rw-r--r--indra/newview/scripts/lua/require/fiber.lua346
-rw-r--r--indra/newview/scripts/lua/require/inspect.lua371
-rw-r--r--indra/newview/scripts/lua/require/leap.lua550
-rw-r--r--indra/newview/scripts/lua/require/login.lua42
-rw-r--r--indra/newview/scripts/lua/require/logout.lua7
-rw-r--r--indra/newview/scripts/lua/require/mapargs.lua73
-rw-r--r--indra/newview/scripts/lua/require/printf.lua19
-rw-r--r--indra/newview/scripts/lua/require/result_view.lua98
-rw-r--r--indra/newview/scripts/lua/require/startup.lua100
-rw-r--r--indra/newview/scripts/lua/require/timers.lua122
-rw-r--r--indra/newview/scripts/lua/require/util.lua114
-rw-r--r--indra/newview/scripts/lua/test_LLAppearance.lua114
-rw-r--r--indra/newview/scripts/lua/test_LLChat.lua18
-rw-r--r--indra/newview/scripts/lua/test_LLChatListener.lua44
-rw-r--r--indra/newview/scripts/lua/test_LLFloaterAbout.lua6
-rw-r--r--indra/newview/scripts/lua/test_LLGesture.lua26
-rw-r--r--indra/newview/scripts/lua/test_LLInventory.lua24
-rw-r--r--indra/newview/scripts/lua/test_animation.lua32
-rw-r--r--indra/newview/scripts/lua/test_atexit.lua3
-rw-r--r--indra/newview/scripts/lua/test_autopilot.lua22
-rw-r--r--indra/newview/scripts/lua/test_callables.lua6
-rw-r--r--indra/newview/scripts/lua/test_camera_control.lua49
-rw-r--r--indra/newview/scripts/lua/test_flycam.lua38
-rw-r--r--indra/newview/scripts/lua/test_group_chat.lua14
-rw-r--r--indra/newview/scripts/lua/test_inv_resultset.lua18
-rw-r--r--indra/newview/scripts/lua/test_login.lua10
-rw-r--r--indra/newview/scripts/lua/test_logout.lua3
-rw-r--r--indra/newview/scripts/lua/test_luafloater_demo.lua39
-rw-r--r--indra/newview/scripts/lua/test_luafloater_gesture_list.lua27
-rw-r--r--indra/newview/scripts/lua/test_luafloater_speedometer.lua31
-rw-r--r--indra/newview/scripts/lua/test_mapargs.lua68
-rw-r--r--indra/newview/scripts/lua/test_nearby_avatars.lua25
-rw-r--r--indra/newview/scripts/lua/test_popup.lua10
-rw-r--r--indra/newview/scripts/lua/test_result_view.lua55
-rw-r--r--indra/newview/scripts/lua/test_screen_position.lua8
-rw-r--r--indra/newview/scripts/lua/test_setdtor.lua91
-rw-r--r--indra/newview/scripts/lua/test_snapshot.lua15
-rw-r--r--indra/newview/scripts/lua/test_timers.lua63
-rw-r--r--indra/newview/scripts/lua/test_toolbars.lua26
-rw-r--r--indra/newview/scripts/lua/test_top_menu.lua52
-rw-r--r--indra/newview/scripts/lua/testmod.lua2
-rw-r--r--indra/newview/skins/default/colors.xml3
-rw-r--r--indra/newview/skins/default/textures/bottomtray/Dpad.pngbin0 -> 765 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Icon_Pointer.pngbin0 -> 294 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.pngbin0 -> 620 bytes
-rw-r--r--indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.pngbin0 -> 485 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml35
-rw-r--r--indra/newview/skins/default/xui/da/sidepanel_item_info.xml3
-rw-r--r--indra/newview/skins/default/xui/da/strings.xml4
-rw-r--r--indra/newview/skins/default/xui/de/floater_about_land.xml3
-rw-r--r--indra/newview/skins/default/xui/de/floater_inspect.xml5
-rw-r--r--indra/newview/skins/default/xui/de/panel_classified_info.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_landmark_info.xml5
-rw-r--r--indra/newview/skins/default/xui/de/panel_place_profile.xml5
-rw-r--r--indra/newview/skins/default/xui/de/panel_profile_classified.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_profile_secondlife.xml6
-rw-r--r--indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/de/panel_status_bar.xml2
-rw-r--r--indra/newview/skins/default/xui/de/sidepanel_item_info.xml5
-rw-r--r--indra/newview/skins/default/xui/de/strings.xml13
-rw-r--r--indra/newview/skins/default/xui/en/control_table_contents_game_control.xml326
-rw-r--r--indra/newview/skins/default/xui/en/floater_about_land.xml3
-rw-r--r--indra/newview/skins/default/xui/en/floater_fast_timers.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_inspect.xml4
-rw-r--r--indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml421
-rw-r--r--indra/newview/skins/default/xui/en/floater_inventory_settings.xml181
-rw-r--r--indra/newview/skins/default/xui/en/floater_joystick.xml68
-rw-r--r--indra/newview/skins/default/xui/en/floater_lua_debug.xml119
-rw-r--r--indra/newview/skins/default/xui/en/floater_lua_scripts.xml37
-rw-r--r--indra/newview/skins/default/xui/en/floater_new_feature_notification.xml12
-rw-r--r--indra/newview/skins/default/xui/en/floater_object_weights.xml110
-rw-r--r--indra/newview/skins/default/xui/en/floater_post_process.xml426
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences.xml25
-rw-r--r--indra/newview/skins/default/xui/en/floater_preview_trash.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_rlv_console.xml74
-rw-r--r--indra/newview/skins/default/xui/en/floater_settings_debug.xml31
-rw-r--r--indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml2
-rw-r--r--indra/newview/skins/default/xui/en/floater_world_map.xml29
-rw-r--r--indra/newview/skins/default/xui/en/game_control_table_camera_rows.xml106
-rw-r--r--indra/newview/skins/default/xui/en/game_control_table_rows.xml106
-rw-r--r--indra/newview/skins/default/xui/en/menu_gallery_inventory.xml146
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml20
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory.xml103
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_inventory_view_default.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_lua_scripts.xml19
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_gallery_sort.xml42
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_gear.xml63
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_list_sort.xml49
-rw-r--r--indra/newview/skins/default/xui/en/menu_outfit_tab.xml20
-rw-r--r--indra/newview/skins/default/xui/en/menu_settings_gear.xml3
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml187
-rw-r--r--indra/newview/skins/default/xui/en/menu_wearable_list_item.xml14
-rw-r--r--indra/newview/skins/default/xui/en/menu_wearing_tab.xml14
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml56
-rw-r--r--indra/newview/skins/default/xui/en/panel_avatar_list_item.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_conversation_list_item.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_roles.xml1179
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml10
-rw-r--r--indra/newview/skins/default/xui/en/panel_landmark_info.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_main_inventory.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_marketplace_listings_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_marketplace_listings_listed.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_marketplace_listings_unassociated.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_marketplace_listings_unlisted.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfit_gallery.xml48
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_list.xml46
-rw-r--r--indra/newview/skins/default/xui/en/panel_outfits_wearing.xml33
-rw-r--r--indra/newview/skins/default/xui/en/panel_place_profile.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_places.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_controls.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_game_control.xml449
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_general.xml31
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_move.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile_pick.xml20
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_general.xml55
-rw-r--r--indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml24
-rw-r--r--indra/newview/skins/default/xui/en/panel_settings_water.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_appearance.xml111
-rw-r--r--indra/newview/skins/default/xui/en/sidepanel_item_info.xml4
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml76
-rw-r--r--indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml3
-rw-r--r--indra/newview/skins/default/xui/en/widgets/folder_view_item.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/output_monitor.xml1
-rw-r--r--indra/newview/skins/default/xui/en/widgets/person_view.xml1
-rw-r--r--indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/es/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/es/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/fr/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/it/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/it/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml4
-rw-r--r--indra/newview/skins/default/xui/ja/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/ja/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/pl/panel_settings_sky_sunmoon.xml4
-rw-r--r--indra/newview/skins/default/xui/pl/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/pl/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/pt/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/ru/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/ru/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/tr/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/tr/strings.xml5
-rw-r--r--indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml2
-rw-r--r--indra/newview/skins/default/xui/zh/panel_snapshot_options.xml2
-rw-r--r--indra/newview/skins/default/xui/zh/strings.xml5
-rw-r--r--indra/newview/tests/cppfeatures_test.cpp2
-rw-r--r--indra/newview/tests/llgamecontrol_stub.cpp99
-rw-r--r--indra/newview/tests/llluamanager_test.cpp523
-rw-r--r--indra/newview/tests/llversioninfo_test.cpp5
-rw-r--r--indra/newview/tests/llviewerhelputil_test.cpp2
-rw-r--r--indra/newview/tests/llworldmap_test.cpp4
-rwxr-xr-xindra/newview/viewer_manifest.py436
578 files changed, 25479 insertions, 7259 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index e14ed53c07..66680513d0 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -32,6 +32,7 @@ include(LLKDU)
include(LLPhysicsExtensions)
include(LLPrimitive)
include(LLWindow)
+include(SDL2)
include(NDOF)
include(NVAPI)
include(OPENAL)
@@ -52,6 +53,7 @@ include(VisualLeakDetector)
include(VulkanGltf)
include(ZLIBNG)
include(LLPrimitive)
+include(Lualibs)
if (ENABLE_MEDIA_PLUGINS)
include(LibVLCPlugin)
@@ -103,6 +105,7 @@ set(viewer_SOURCE_FILES
llagentwearables.cpp
llanimstatelabels.cpp
llappcorehttp.cpp
+ llappearancelistener.cpp
llappearancemgr.cpp
llappviewer.cpp
llappviewerlistener.cpp
@@ -258,6 +261,8 @@ set(viewer_SOURCE_FILES
llfloaterlandholdings.cpp
llfloaterlinkreplace.cpp
llfloaterloadprefpreset.cpp
+ llfloaterluadebug.cpp
+ llfloaterluascripts.cpp
llfloatermarketplacelistings.cpp
llfloatermap.cpp
llfloatermediasettings.cpp
@@ -280,7 +285,6 @@ set(viewer_SOURCE_FILES
llfloaterpay.cpp
llfloaterperformance.cpp
llfloaterperms.cpp
- llfloaterpostprocess.cpp
llfloaterprofile.cpp
llfloaterpreference.cpp
llfloaterpreferencesgraphicsadvanced.cpp
@@ -326,6 +330,7 @@ set(viewer_SOURCE_FILES
llfollowcam.cpp
llfriendcard.cpp
llflyoutcombobtn.cpp
+ llflycam.cpp
llgesturelistener.cpp
llgesturemgr.cpp
llgiveinventory.cpp
@@ -347,6 +352,7 @@ set(viewer_SOURCE_FILES
llhudeffectpointat.cpp
llhudeffecttrail.cpp
llhudeffectblob.cpp
+ llhudeffectresetskeleton.cpp
llhudicon.cpp
llhudmanager.cpp
llhudnametag.cpp
@@ -372,6 +378,7 @@ set(viewer_SOURCE_FILES
llinventorygallerymenu.cpp
llinventoryicon.cpp
llinventoryitemslist.cpp
+ llinventorylistener.cpp
llinventorylistitem.cpp
llinventorymodel.cpp
llinventorymodelbackgroundfetch.cpp
@@ -391,6 +398,7 @@ set(viewer_SOURCE_FILES
lllogchat.cpp
llloginhandler.cpp
lllogininstance.cpp
+ llluamanager.cpp
llmachineid.cpp
llmanip.cpp
llmaniprotate.cpp
@@ -740,6 +748,11 @@ set(viewer_SOURCE_FILES
llxmlrpctransaction.cpp
noise.cpp
pipeline.cpp
+ rlvactions.cpp
+ rlvcommon.cpp
+ rlvfloaters.cpp
+ rlvhelper.cpp
+ rlvhandler.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES FreeBSD)
@@ -776,6 +789,7 @@ set(viewer_HEADER_FILES
llanimstatelabels.h
llappcorehttp.h
llappearance.h
+ llappearancelistener.h
llappearancemgr.h
llappviewer.h
llappviewerlistener.h
@@ -934,6 +948,8 @@ set(viewer_HEADER_FILES
llfloaterlandholdings.h
llfloaterlinkreplace.h
llfloaterloadprefpreset.h
+ llfloaterluadebug.h
+ llfloaterluascripts.h
llfloatermap.h
llfloatermarketplacelistings.h
llfloatermediasettings.h
@@ -956,7 +972,6 @@ set(viewer_HEADER_FILES
llfloaterpay.h
llfloaterperformance.h
llfloaterperms.h
- llfloaterpostprocess.h
llfloaterprofile.h
llfloaterpreference.h
llfloaterpreferencesgraphicsadvanced.h
@@ -1002,6 +1017,7 @@ set(viewer_HEADER_FILES
llfollowcam.h
llfriendcard.h
llflyoutcombobtn.h
+ llflycam.h
llgesturelistener.h
llgesturemgr.h
llgiveinventory.h
@@ -1022,6 +1038,7 @@ set(viewer_HEADER_FILES
llhudeffectpointat.h
llhudeffecttrail.h
llhudeffectblob.h
+ llhudeffectresetskeleton.h
llhudicon.h
llhudmanager.h
llhudnametag.h
@@ -1046,6 +1063,7 @@ set(viewer_HEADER_FILES
llinventorygallerymenu.h
llinventoryicon.h
llinventoryitemslist.h
+ llinventorylistener.h
llinventorylistitem.h
llinventorymodel.h
llinventorymodelbackgroundfetch.h
@@ -1065,6 +1083,7 @@ set(viewer_HEADER_FILES
lllogchat.h
llloginhandler.h
lllogininstance.h
+ llluamanager.h
llmachineid.h
llmanip.h
llmaniprotate.h
@@ -1406,6 +1425,12 @@ set(viewer_HEADER_FILES
llxmlrpctransaction.h
noise.h
pipeline.h
+ rlvdefines.h
+ rlvactions.h
+ rlvcommon.h
+ rlvfloaters.h
+ rlvhelper.h
+ rlvhandler.h
roles_constants.h
VertexCache.h
VorbisFramework.h
@@ -1636,6 +1661,13 @@ set_source_files_properties(${viewer_SHADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
list(APPEND viewer_SOURCE_FILES ${viewer_SHADER_FILES})
+# Add lua script sources
+file(GLOB_RECURSE viewer_LUA_SCRIPT_FILES LIST_DIRECTORIES FALSE
+ ${CMAKE_CURRENT_SOURCE_DIR}/scripts/lua/*.lua)
+source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/lua PREFIX "LUA Scripts" FILES ${viewer_LUA_SCRIPT_FILES})
+set_source_files_properties(${viewer_LUA_SCRIPT_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+list(APPEND viewer_SOURCE_FILES ${viewer_LUA_SCRIPT_FILES})
set(viewer_APPSETTINGS_FILES
app_settings/anim.ini
@@ -1657,6 +1689,7 @@ set(viewer_APPSETTINGS_FILES
app_settings/toolbars.xml
app_settings/trees.xml
app_settings/viewerart.xml
+ app_settings/gamecontrollerdb.txt
${CMAKE_SOURCE_DIR}/../etc/message.xml
${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
packages-info.txt
@@ -1754,7 +1787,7 @@ if (WINDOWS)
# And of course it's straightforward to read a text file in Python.
set(COPY_INPUT_DEPENDENCIES
- # The following commented dependencies are determined at variably at build time. Can't do this here.
+ # The following commented dependencies are determined variably at build time. Can't do this here.
${CMAKE_SOURCE_DIR}/../etc/message.xml
${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
${SHARED_LIB_STAGING_DIR}/openjp2.dll
@@ -1840,20 +1873,6 @@ if (WINDOWS)
if (PACKAGE)
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz
- COMMAND ${PYTHON_EXECUTABLE}
- ARGS
- ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py
- ${CMAKE_CURRENT_SOURCE_DIR}/..
- ${CMAKE_CURRENT_BINARY_DIR}
- ${CMAKE_CFG_INTDIR}
- DEPENDS
- lleventhost
- ${EVENT_HOST_SCRIPTS}
- ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py
- )
-
- add_custom_command(
OUTPUT ${CMAKE_CFG_INTDIR}/touched.bat
COMMAND ${PYTHON_EXECUTABLE}
ARGS
@@ -1882,9 +1901,6 @@ if (WINDOWS)
add_custom_target(llpackage ALL DEPENDS
${CMAKE_CFG_INTDIR}/touched.bat
)
- # temporarily disable packaging of event_host until hg subrepos get
- # sorted out on the parabuild cluster...
- #${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz)
endif (PACKAGE)
elseif (DARWIN)
@@ -1896,7 +1912,7 @@ else (WINDOWS)
# Linux
set_target_properties(${VIEWER_BINARY_NAME}
PROPERTIES
- LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Wl,--Map=${VIEWER_BINARY_NAME}.MAP"
+ LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -no-pie -Wl,--Map=${VIEWER_BINARY_NAME}.MAP"
)
endif (WINDOWS)
@@ -1945,12 +1961,14 @@ target_link_libraries(${VIEWER_BINARY_NAME}
llcorehttp
llcommon
llmeshoptimizer
- ll::ndof
+ llwebrtc
lllogin
llprimitive
llappearance
${LLPHYSICSEXTENSIONS_LIBRARIES}
ll::bugsplat
+ ll::lualibs
+ ll::ndof
ll::tracy
ll::openxr
)
@@ -2490,6 +2508,7 @@ if (LL_TESTS)
lllogin
llplugin
llappearance
+ ll::SDL2
)
set_source_files_properties(
@@ -2541,6 +2560,7 @@ if (LL_TESTS)
lllogin
llprimitive
lllogin
+ ll::SDL2
)
LL_ADD_INTEGRATION_TEST(cppfeatures
@@ -2548,6 +2568,11 @@ if (LL_TESTS)
"${test_libs}"
)
+ LL_ADD_INTEGRATION_TEST(llluamanager
+ "llluamanager.cpp"
+ "${test_libs};ll::lualibs"
+ )
+
LL_ADD_INTEGRATION_TEST(llsechandler_basic
llsechandler_basic.cpp
"${test_libs}"
diff --git a/indra/newview/FixBundle.cmake.in b/indra/newview/FixBundle.cmake.in
index bf3a36b5d0..dbf9161b70 100644
--- a/indra/newview/FixBundle.cmake.in
+++ b/indra/newview/FixBundle.cmake.in
@@ -90,6 +90,11 @@ file(CREATE_LINK
SYMBOLIC
)
file(CREATE_LINK
+ "../../../../Frameworks/libSDL2-2.0.0.dylib"
+ "${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/libSDL2-2.0.0.dylib"
+ SYMBOLIC
+ )
+file(CREATE_LINK
"../../../../Frameworks/libfreetype.6.dylib"
"${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/libfreetype.6.dylib"
SYMBOLIC
@@ -279,6 +284,7 @@ execute_process(
Frameworks/Chromium\ Embedded\ Framework.framework/Libraries/libGLESv2.dylib
Frameworks/Chromium\ Embedded\ Framework.framework/Libraries/libvk_swiftshader.dylib
Frameworks/Chromium\ Embedded\ Framework.framework
+ Frameworks/libSDL2-2.0.0.dylib
Frameworks/libalut.0.dylib
Frameworks/libapr-1.0.dylib
Frameworks/libaprutil-1.0.dylib
diff --git a/indra/newview/FixPackage.cmake.in b/indra/newview/FixPackage.cmake.in
index 2dec79c59b..d8c91afce2 100644
--- a/indra/newview/FixPackage.cmake.in
+++ b/indra/newview/FixPackage.cmake.in
@@ -90,6 +90,11 @@ file(CREATE_LINK
SYMBOLIC
)
file(CREATE_LINK
+ "../../../../Frameworks/libSDL2-2.0.0.dylib"
+ "${CMAKE_CACHEFILE_DIR}/_CPack_Packages/${CMAKE_SYSTEM_NAME}/Bundle/${CPACK_BUNDLE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}/${CPACK_BUNDLE_NAME}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/libSDL2-2.0.0.dylib"
+ SYMBOLIC
+ )
+file(CREATE_LINK
"../../../../Frameworks/libfreetype.6.dylib"
"${CMAKE_CACHEFILE_DIR}/_CPack_Packages/${CMAKE_SYSTEM_NAME}/Bundle/${CPACK_BUNDLE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}/${CPACK_BUNDLE_NAME}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/libfreetype.6.dylib"
SYMBOLIC
@@ -279,6 +284,7 @@ execute_process(
Frameworks/Chromium\ Embedded\ Framework.framework/Libraries/libGLESv2.dylib
Frameworks/Chromium\ Embedded\ Framework.framework/Libraries/libvk_swiftshader.dylib
Frameworks/Chromium\ Embedded\ Framework.framework
+ Frameworks/libSDL2-2.0.0.dylib
Frameworks/libalut.0.dylib
Frameworks/libapr-1.0.dylib
Frameworks/libaprutil-1.0.dylib
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index e0eaaa0bbc..0f9f025fe4 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-7.1.11
+7.1.12
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index e16a5c7e76..e610775332 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -195,7 +195,33 @@
<string>LogPerformance</string>
</map>
- <key>multiple</key>
+ <key>lua</key>
+ <map>
+ <key>desc</key>
+ <string>Run specified Lua chunk</string>
+ <key>count</key>
+ <integer>1</integer>
+ <!-- you can specify multiple such chunks -->
+ <key>compose</key>
+ <boolean>true</boolean>
+ <key>map-to</key>
+ <string>LuaChunk</string>
+ </map>
+
+ <key>luafile</key>
+ <map>
+ <key>desc</key>
+ <string>Run specified Lua script</string>
+ <key>count</key>
+ <integer>1</integer>
+ <!-- you can specify multiple such scripts -->
+ <key>compose</key>
+ <boolean>true</boolean>
+ <key>map-to</key>
+ <string>LuaScript</string>
+ </map>
+
+ <key>multiple</key>
<map>
<key>desc</key>
<string>Allow multiple viewers.</string>
diff --git a/indra/newview/app_settings/gamecontrollerdb.txt b/indra/newview/app_settings/gamecontrollerdb.txt
new file mode 100644
index 0000000000..edf904a65a
--- /dev/null
+++ b/indra/newview/app_settings/gamecontrollerdb.txt
@@ -0,0 +1,2043 @@
+# Game Controller DB for SDL in 2.0.16 format
+# Source: https://github.com/gabomdq/SDL_GameControllerDB
+
+# Windows
+03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,
+03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,
+03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
+03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
+03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
+03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
+03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
+03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,
+03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00002090000000000000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,
+03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows,
+03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
+03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
+03000000c82d00006928000000000000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows,
+03000000c82d00002590000000000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+030000003512000012ab000000000000,8BitDo NES30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Windows,
+03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows,
+03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001630000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001730000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
+030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000fa190000f0ff000000000000,Acteck AGJ 3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows,
+030000006f0e00008801000000000000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001301000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e00001302000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e00001304000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e00001413000000000000,Afterglow Xbox Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00003901000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ab1200000103000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b000000f9000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000100000008200000000000000,Akishop Customs PS360,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000007c1800000006000000000000,Alienware Dual Compatible PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
+03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows,
+0300000008100000e501000000000000,Anbernic Game Pad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows,
+03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,start:b3,platform:Windows,
+03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
+030000008a3500000102000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,
+030000008a3500000201000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,
+030000008a3500000302000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,
+030000008a3500000402000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,
+03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,
+030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows,
+030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
+03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
+030000006f0e00006401000000000000,BF One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
+03000000300f00000202000000000000,Bigben,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a5,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
+030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
+03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
+030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
+030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
+030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000b0400003365000000000000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
+030000004c050000c505000000000000,CronusMax Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000d814000007cd000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000d8140000cefa000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows,
+030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows,
+030000001a1c00000001000000000000,Datel Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000c0160000e105000000000000,Dual Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,platform:Windows,
+030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
+030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
+03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
+03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows,
+030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
+03000000317300000100000000000000,DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+03000000bc2000000091000000000000,EasySMX Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows,
+03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
+03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
+030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
+03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
+030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
+030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
+030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
+030000006e0500001320000000000000,Elecom U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006e0500001020000000000000,Elecom U4113S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
+030000006e0500000720000000000000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
+030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows,
+03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows,
+03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
+03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00008101000000000000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+03000000852100000201000000000000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+03005036852100000000000000000000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows,
+03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,
+03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,
+03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,
+03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,
+03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
+0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
+03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,
+03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows,
+03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows,
+03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000ac0500003d03000000000000,GameSir G3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000ac0500001a06000000000000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows,
+030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000c9110000f055000000000000,GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000007d0400000840000000000000,Gravis Destroyer Tilt,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,
+030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+03000000280400000140000000000000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
+03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
+030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
+03000000632500002605000000000000,HJD X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00008500000000000000,Hori Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006201000000000000,Hori Fighting Commander Octa,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006401000000000000,Hori Fighting Commander Octa,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
+030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows,
+030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,
+030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00003801000000000000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Windows,
+030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00002301000000000000,Hori PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+030000000d0f00001100000000000000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00004b00000000000000,Hori Real Arcade Pro 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00008a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00008b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006f00000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00007000000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00003d00000000000000,Hori Real Arcade Pro N3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b4,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b6,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000ae00000000000000,Hori Real Arcade Pro N4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00008c00000000000000,Hori Real Arcade Pro P4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f0000aa00000000000000,Hori Real Arcade Pro S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000d800000000000000,Hori Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows,
+030000000d0f00002200000000000000,Hori Real Arcade Pro V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00005b00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows,
+030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006400000000000000,Horipad 3TP,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006e00000000000000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00004200000000000000,Horipad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
+03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
+03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
+03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows,
+03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows,
+03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
+03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000005c0a00000285000000000000,iDroidCon,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b6,platform:Windows,
+03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000511d00000230000000000000,iGUGU Gamecore,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b1,leftstick:b4,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b2,platform:Windows,
+03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
+03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
+03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows,
+03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows,
+03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
+03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows,
+03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows,
+03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,
+030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows,
+030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,
+03000000250900000017000000000000,Joypad Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows,
+03000000bd12000003c0000000000000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000ff1100004033000000000000,JPD FFB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a2,start:b15,x:b3,y:b0,platform:Windows,
+03000000242f00002d00000000000000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
+03000000c4100000c082000000000000,KADE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,platform:Windows,
+03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
+03000000bd12000001e0000000000000,Leadership,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+030000006f0e00000103000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e00000104000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000008f0e00001300000000000000,Logic3,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
+030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
+030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows,
+030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
+03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700003888000000000000,Mad Catz Arcade Fightstick TE S Plus PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
+030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,
+030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
+0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows,
+03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
+030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
+03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
+03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,
+0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,righttrigger:b2,start:b3,platform:Windows,
+030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows,
+030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
+030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows,
+030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Windows,
+03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows,
+03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000004523000015e0000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000491900000904000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows,
+03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
+03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
+03000000d6200000ad0d000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000c62400002a89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
+03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
+030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows,
+030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+0300000085320000190d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows,
+0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows,
+03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,
+03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,
+03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,
+03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,
+03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows,
+03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
+030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,
+030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows,
+030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows,
+03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,
+03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows,
+030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+030000004b120000014d000000000000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000d62000001d57000000000000,Nyko Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows,
+030000000d0f00000401000000000000,Onyx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000008916000001fd000000000000,Onza CE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
+03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows,
+03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
+03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000632500002306000000000000,PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
+03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000d620000011a7000000000000,PowerA Core Plus GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000c62400001a53000000000000,Pro Ex Mini,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000110e000000000000,Pro5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000151a00006222000000000000,PS2 Dual Plus Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000120a00000100000000000000,PS3 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000250900000218000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,
+030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,
+030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
+03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
+030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
+030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
+03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004c0500005f0e000000000000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows,
+03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000300f00000011000000000000,Qanba Arcade Stick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,
+03000000300f00001611000000000000,Qanba Arcade Stick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
+03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000222c00000020000000000000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00001211000000000000,Qanba Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,
+03000000341a00000104000000000000,Qanba Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,
+03000000222c00000223000000000000,Qanba Obsidian Arcade Stick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows,
+03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
+03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
+030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
+030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
+030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows,
+030000009b280000d000000000000000,Raphnet Dreamcast Adapter,a:b1,b:b0,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,lefttrigger:+a5,leftx:a0,lefty:a1,righttrigger:+a2,start:b3,x:b5,y:b4,platform:Windows,
+030000009b2800006200000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
+030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
+030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
+030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
+030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
+030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
+030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
+030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
+030000009b2800002600000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800002e00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800002f00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,
+030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
+030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
+03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
+03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows,
+03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000321500000710000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows,
+03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
+03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
+0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
+03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
+03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows,
+0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
+0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
+03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows,
+030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001f01000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e00004601000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000c6240000fefa000000000000,Rock Candy Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e00008701000000000000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
+030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
+030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows,
+030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,
+03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,
+03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows,
+03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b8,x:b0,y:b3,platform:Windows,
+03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000a306000018f5000000000000,Saitek P3200,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,platform:Windows,
+03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
+03000000a30600002106000000000000,Saitek PS1000 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
+03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows,
+03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows,
+03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
+03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows,
+03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,
+03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows,
+03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
+03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
+0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
+0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
+03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
+03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
+030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
+03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows,
+03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
+030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
+03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
+03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
+03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows,
+030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
+03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
+03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,
+03000000790000001c18000000000000,STK 7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
+030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,platform:Windows,
+03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,
+030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000e40a00000307000000000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,
+03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,
+03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
+03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
+03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
+03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows,
+030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
+030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f04000008d0000000000000,ThrustMaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,
+030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
+030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows,
+03000000571d00002000000000000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,
+03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
+03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000151900005678000000000000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+030000000b0400003065000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
+03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows,
+03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
+03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
+03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
+03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
+03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,
+03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
+0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700002045000000000000,Xbox 360 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700002644000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a5,start:b8,x:b2,y:b3,platform:Windows,
+03000000380700002647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000003807000026b7000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700003647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a7,righty:a5,start:b7,x:b2,y:b3,platform:Windows,
+030000005e0400001907000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e0400009102000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b000000fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b000001fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b000016f0000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000ad1b00008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000c62400000053000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000c6240000fdfa000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000a102000000000000,Xbox 360 Wireless Receiver,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000120c00000a88000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000120c00001088000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2~,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5~,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000002a0600002000000000000000,Xbox Controller,a:b0,b:b1,back:b13,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b5,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b15,righttrigger:b7,rightx:a2,righty:a5,start:b12,x:b2,y:b3,platform:Windows,
+03000000300f00008888000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:b13,dpleft:b10,dpright:b11,dpup:b12,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000380700001645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000380700002645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000380700003645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+03000000380700008645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e0400000202000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+030000005e0400008502000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e0400008702000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+030000005e0400008902000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b8,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b9,righttrigger:b4,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
+030000000d0f00006300000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e0400000c0b000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
+03000000e0ff00000201000000000000,Xiaomi Black Shark (L),back:b0,dpdown:b11,dpleft:b9,dpright:b10,dpup:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,platform:Windows,
+03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,
+xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows,
+030000002c3600000100000000000000,Yawman Arrow,+rightx:h0.2,+righty:h0.4,-rightx:h0.8,-righty:h0.1,a:b4,b:b5,back:b6,dpdown:b15,dpleft:b14,dpright:b16,dpup:b13,leftshoulder:b10,leftstick:b0,lefttrigger:-a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b12,rightshoulder:b8,rightstick:b9,righttrigger:+a4,start:b3,x:b1,y:b2,platform:Windows,
+03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,
+03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+
+# Mac OS X
+030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
+03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X,
+03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
+03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
+03000000c82d00002590000000010000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00002690000000010000,8BitDo NEOGEO,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b10,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00003028000000010000,8Bitdo SFC30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001530000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,
+03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
+0300000008100000e501000019040000,Anbernic Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
+03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
+03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
+03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
+030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
+030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000008a3500000302000000010000,Backbone One PlayStationÆ Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
+03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
+03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
+03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Mac OS X,
+030000006f0e00008401000003010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Mac OS X,
+03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
+03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X,
+030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,
+030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
+030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f0000c100000072050000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X,
+03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X,
+03000000830500006020000000000000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,
+03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,
+03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Mac OS X,
+030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000006d04000019c2000000000000,Logitech Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d04000016c2000000000000,Logitech F310,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X,
+03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
+03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,
+0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X,
+0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,
+03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X,
+03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
+03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
+030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X,
+030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Mac OS X,
+030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Mac OS X,
+030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,
+030000004523000015e0000072050000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
+03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X,
+030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X,
+050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X,
+030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X,
+030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
+030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X,
+030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000666600006706000088020000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,
+030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
+030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
+030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
+030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+0300004b4c0500005f0e000000010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
+03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000009b2800005600000020020000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Mac OS X,
+030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Mac OS X,
+030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
+030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
+0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X,
+03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X,
+0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Mac OS X,
+03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X,
+030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X,
+030000006f0e00008701000005010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000e804000000a000001b010000,Samsung EIGP20,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b11,leftx:a1,lefty:a3,rightshoulder:b12,rightx:a4,righty:a5,start:b16,x:b7,y:b9,platform:Mac OS X,
+03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X,
+03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X,
+03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
+03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
+030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
+030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
+030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
+03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
+03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
+05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
+050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
+03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
+03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
+030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
+03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
+03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
+03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
+030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
+030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
+03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X,
+03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
+030000005f140000c501000000020000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,
+03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000151900005678000010010000,Uniplay U6,a:b3,b:b6,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,leftstick:b31,lefttrigger:b21,leftx:a1,lefty:a3,rightshoulder:b19,rightstick:b33,righttrigger:b23,rightx:a4,righty:a5,start:b27,x:b11,y:b13,platform:Mac OS X,
+030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,
+050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,
+030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000200b000015050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
+030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+
+# Linux
+03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
+03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00002090000011010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
+03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux,
+05000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
+05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
+03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000020000000000000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+06000000c82d00000020000006010000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux,
+05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
+030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000631000010010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000631000014010000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
+05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
+05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00008801000011010000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00001302000000010000,Afterglow Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00003901000020060000,Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000007c1800000006000010010000,Alienware Dual Compatible Game PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
+05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
+05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
+0300000008100000e501000001010000,Anbernic Gamepad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux,
+03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
+03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
+05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
+03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+03000000503200000110000011010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+05000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+05000000503200000110000044010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+05000000503200000110000046010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,
+03000000503200000210000011010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
+05000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
+05000000503200000210000045010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
+05000000503200000210000046010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
+05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,
+030000008a3500000201000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000008a3500000202000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000008a3500000302000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000008a3500000402000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000bc2000004d50000011010000,Beitong A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
+030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
+03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,
+03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000242f00009100000000010000,EasySMX ESM-9101,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,
+030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
+030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
+03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
+030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
+19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux,
+190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux,
+190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux,
+03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000001010000,GPD Win Max 2 (6800U) Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,
+030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,
+03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux,
+030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
+030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux,
+030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00001100000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
+030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
+05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux,
+03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux,
+03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux,
+03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
+030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux,
+050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
+03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
+03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
+03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
+03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Linux,
+03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,
+0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
+03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
+03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
+030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,
+050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux,
+030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,
+050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux,
+03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
+030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006d0400001ec2000019200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006d0400001ec2000020200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006d04000019c2000011010000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
+030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
+05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
+03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
+03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
+0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
+0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
+03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
+03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
+03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
+03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
+030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
+030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
+030000005e0400000700000000010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
+030000005e0400000e00000000010000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,
+030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux,
+030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+030000005e0400008902000021010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
+03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
+05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
+05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
+03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
+030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00001311000011010000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Linux,
+030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
+03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,
+060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
+030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
+03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,
+060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,
+030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Linux,
+030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
+05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
+030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
+030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
+050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux,
+050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
+030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
+050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux,
+050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
+03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
+05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
+030000004b120000014d000000010000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
+19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
+05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
+05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
+05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux,
+03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
+03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
+030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
+03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
+030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d620000011a7000011010000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d620000013a7000011010000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000d620000014a7000011010000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
+03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
+03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
+030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
+030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000005f1400003102000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
+050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
+050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
+060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
+030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+0300004b4c0500005f0e000011010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
+03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
+03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
+030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,
+030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
+030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
+030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux,
+03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
+050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
+0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
+0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
+190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,
+0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
+00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux,
+03000000341200000400000000010000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Linux,
+030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00008701000011010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,
+03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,
+03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,
+03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,
+03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
+03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,
+03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
+03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,
+03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
+03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
+03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
+03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
+030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
+03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000632500002605000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
+03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
+030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
+05000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000512000010010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux,
+03000000de2800000512000011010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux,
+03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,
+03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
+03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
+0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
+030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
+03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
+03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux,
+03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
+03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
+030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004f0400000ed0000011010000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,
+030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux,
+030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,
+030000004f04000004b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+030000004f04000026b3000002040000,Thrustmaster GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c6240000025b000002020000,Thrustmaster GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000004f04000008d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004f04000009d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000004f04000007d0000000010000,Thrustmaster T Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000004f04000012b3000010010000,Thrustmaster Vibrating Gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
+03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
+03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
+03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
+030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
+030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
+03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
+03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,
+03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
+030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
+030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+0000000058626f782047616d65706100,Xbox Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
+030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000007050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
+03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,
+030000005e0400008e02000020010000,XInput Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+
+# Android
+38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android,
+38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android,
+32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android,
+38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android,
+64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android,
+66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android,
+66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android,
+38426974446f204d6963726f2067616d,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
+61653365323561356263373333643266,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
+62613137616239666338343866326336,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
+33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38323035343766666239373834336637,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android,
+38426974446f204e3634204d6f646b69,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android,
+32363135613966656338666638666237,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35363534633333373639386466346631,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f204e454f47454f204750,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39383963623932353561633733306334,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android,
+38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,platform:Android,
+38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android,
+61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android,
+05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000002600000ffff0f00,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
+33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
+63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+4c696e757820342e31392e3137322077,Anbernic Gamepad,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
+35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,start:b6,platform:Android,
+32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android,
+05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
+65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b18,platform:Android,
+31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+32656664353964393561366362333636,Hori Switch Split Pad Pro,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+48797065726b696e2050616400000000,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android,
+62333331353131353034386136626636,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android,
+31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android,
+5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android,
+64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android,
+532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android,
+65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android,
+33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
+35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
+4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
+38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android,
+64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android,
+6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android,
+436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+37316565396364386635383230353365,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
+4875694a696120205553422047616d65,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
+535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+39346131396233376535393665363161,Mayflash Wii U Pro Adapter,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftstick:b31,lefttrigger:b27,rightshoulder:b26,rightstick:b0,righttrigger:b28,rightx:a0,righty:a1,start:b30,x:b21,y:b24,platform:Android,
+31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
+37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
+64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Android,
+33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android,
+30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android,
+32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android,
+050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android,
+34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android,
+36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
+4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
+534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+050000005509000014720000df7f3f80,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
+4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
+506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
+62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android,
+536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android,
+32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android,
+050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000c4050000fffe3f80,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000004c050000cc090000fffe3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android,
+31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000e60c0000fffe3f80,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android,
+32417865732031314b6579732047616d,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+36313938306539326233393732613361,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android,
+61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android,
+526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b6,platform:Android,
+37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android,
+5365616c6965436f6d707574696e6720,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android,
+526574726f5553422e636f6d20534e45,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android,
+64643037633038386238303966376137,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android,
+37656564346533643138636436356230,Rock Candy Switch Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android,
+36363537303435333566386638366333,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+53616d73756e672047616d6520506164,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,platform:Android,
+32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android,
+38613865396530353338373763623431,Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b10,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,platform:Android,
+61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android,
+30353835333338613130373363646337,SG H510,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+66386262366536653765333235343634,SG H510,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
+5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
+5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android,
+63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android,
+476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+5374616469614e3848532d6532633400,Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
+05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
+0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android,
+35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android,
+33313930373536613937326534303931,Taito Egret II Mini Control Panel,a:b25,b:b23,back:b27,guide:b30,leftx:a0,lefty:a1,rightshoulder:b21,righttrigger:b22,start:b28,x:b29,y:b24,platform:Android,
+54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,platform:Android,
+38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,platform:Android,
+050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
+30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+30386438313564306161393537333663,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+33333034646336346339646538643633,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+050000005e04000091020000ff073f80,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
+050000005e040000e00200000ffe3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android,
+050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
+050000005e040000e0020000ffff3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android,
+050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,
+35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000120b000000783f80,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+
+# iOS
+05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
+05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
+05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
+05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,
+05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,
+050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,
+4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,
+050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS,
+050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS,
+050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,
+050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS,
+050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,
+050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000004c050000e60c0000df870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,touchpad:b10,x:b2,y:b3,platform:iOS,
+050000004c050000e60c0000ff870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,
+05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
+05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
+05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
+05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
+050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a8a8f1b6cf..c4c5d88446 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -79,7 +79,7 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>CrashHostUrl</key>
+ <key>CrashHostUrl</key>
<map>
<key>Comment</key>
<string>A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.</string>
@@ -93,16 +93,16 @@
<key>AFKTimeout</key>
<map>
<key>Comment</key>
- <string>
- Time before automatically setting AFK (away from keyboard) mode (seconds, 0=never).
- Valid values are: 0, 120, 300, 600, 1800
-</string>
+ <string>
+ Time before automatically setting AFK (away from keyboard) mode (seconds, 0=never).
+ Valid values are: 0, 120, 300, 600, 1800
+ </string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
- <real>300.0</real>
+ <real>300</real>
</map>
<key>AckCollectTime</key>
<map>
@@ -357,7 +357,7 @@
<key>Value</key>
<real>0.5</real>
</map>
- <key>AudioStreamingMedia</key>
+ <key>AudioStreamingMedia</key>
<map>
<key>Comment</key>
<string>Enable streaming</string>
@@ -390,7 +390,7 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>AutoAcceptNewInventory</key>
+ <key>AutoAcceptNewInventory</key>
<map>
<key>Comment</key>
<string>Automatically accept new notecards/textures/landmarks</string>
@@ -1325,7 +1325,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>0</integer>
</map>
<key>CameraPositionSmoothing</key>
<map>
@@ -1864,6 +1864,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>DebugSelectionLODs</key>
+ <map>
+ <key>Comment</key>
+ <string>Force selection to show specific LOD, -1 for off, 0 - lowest, 4 - high.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
<key>AnimatedObjectsAllowLeftClick</key>
<map>
<key>Comment</key>
@@ -1963,17 +1974,17 @@
<key>Value</key>
<string />
</map>
- <key>DebugAvatarRezTime</key>
- <map>
- <key>Comment</key>
- <string>Display times for avatars to resolve.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
+ <key>DebugAvatarRezTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Display times for avatars to resolve.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>DebugAvatarLocalTexLoadedTime</key>
<map>
<key>Comment</key>
@@ -2348,39 +2359,39 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>DefaultFemaleAvatar</key>
- <map>
- <key>Comment</key>
- <string>Default Female Avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Female Shape &amp; Outfit</string>
- </map>
- <key>DefaultLoginLocation</key>
- <map>
- <key>Comment</key>
- <string>Startup destination default (if not specified on command line)</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string/>
- </map>
- <key>DefaultMaleAvatar</key>
- <map>
- <key>Comment</key>
- <string>Default Male Avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Male Shape &amp; Outfit</string>
- </map>
+ <key>DefaultFemaleAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Default Female Avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Female Shape &amp; Outfit</string>
+ </map>
+ <key>DefaultLoginLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Startup destination default (if not specified on command line)</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string/>
+ </map>
+ <key>DefaultMaleAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Default Male Avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Male Shape &amp; Outfit</string>
+ </map>
<key>DestinationGuideURL</key>
<map>
<key>Comment</key>
@@ -2634,6 +2645,94 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>EnableGameControl</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable GameControl feature</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>GameControlToServer</key>
+ <map>
+ <key>Comment</key>
+ <string>Transmit game controller data to server</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>GameControlToAgent</key>
+ <map>
+ <key>Comment</key>
+ <string>GameControl data moves avatar/flycam</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AgentToGameControl</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar/flycam movement produces GameControl data</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AnalogChannelMappings</key>
+ <map>
+ <key>Comment</key>
+ <string>GameControl analog button to channel mappings</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>push:AXIS_1+,slide:AXIS_0+,jump:AXIS_4+,turn:AXIS_2+,look:AXIS_3+</string>
+ </map>
+ <key>BinaryChannelMappings</key>
+ <map>
+ <key>Comment</key>
+ <string>GameControl binary button to channel mappings</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>toggle_run:BUTTON_9,toggle_fly:BUTTON_11,toggle_flycam:BUTTON_10,stop:BUTTON_7</string>
+ </map>
+ <key>FlycamChannelMappings</key>
+ <map>
+ <key>Comment</key>
+ <string>GameControl flycam button to channel mappings</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>advance:AXIS_1+,pan:AXIS_0+,rise:AXIS_5+,pitch:AXIS_3-,yaw:AXIS_2+</string>
+ </map>
+ <key>KnownGameControllers</key>
+ <map>
+ <key>Comment</key>
+ <string>Map of controller device-specific options.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <map/>
+ </map>
<key>EnableGestureSounds</key>
<map>
<key>Comment</key>
@@ -2766,7 +2865,7 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>FirstSelectedEnabledPopups</key>
+ <key>FirstSelectedEnabledPopups</key>
<map>
<key>Comment</key>
<string>Return false if there is not enable popup selected in the list of floater preferences popups</string>
@@ -3588,39 +3687,39 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>InventoryLinking</key>
- <map>
- <key>Comment</key>
- <string>Enable ability to create links to folders and items via "Paste as link".</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>InventoryOutboxLogging</key>
- <map>
- <key>Comment</key>
- <string>Enable debug output associated with the Merchant Outbox.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>InventoryOutboxMakeVisible</key>
- <map>
- <key>Comment</key>
- <string>Enable making the Merchant Outbox and Inbox visible in the inventory for debug purposes.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
+ <key>InventoryLinking</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable ability to create links to folders and items via "Paste as link".</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>InventoryOutboxLogging</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable debug output associated with the Merchant Outbox.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>InventoryOutboxMakeVisible</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable making the Merchant Outbox and Inbox visible in the inventory for debug purposes.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>InventoryOutboxMaxFolderCount</key>
<map>
<key>Comment</key>
@@ -3874,8 +3973,8 @@
<key>Value</key>
<real>0.25</real>
</map>
- <key>Jpeg2000AdvancedCompression</key>
- <map>
+ <key>Jpeg2000AdvancedCompression</key>
+ <map>
<key>Comment</key>
<string>Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers)</string>
<key>Persist</key>
@@ -3884,9 +3983,9 @@
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
- </map>
- <key>Jpeg2000PrecinctsSize</key>
- <map>
+ </map>
+ <key>Jpeg2000PrecinctsSize</key>
+ <map>
<key>Comment</key>
<string>Size of image precincts. Assumed square and same for all levels. Must be power of 2.</string>
<key>Persist</key>
@@ -3895,9 +3994,9 @@
<string>S32</string>
<key>Value</key>
<integer>256</integer>
- </map>
- <key>Jpeg2000BlocksSize</key>
- <map>
+ </map>
+ <key>Jpeg2000BlocksSize</key>
+ <map>
<key>Comment</key>
<string>Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4.</string>
<key>Persist</key>
@@ -3906,7 +4005,7 @@
<string>S32</string>
<key>Value</key>
<integer>64</integer>
- </map>
+ </map>
<key>KeepAspectForSnapshot</key>
<map>
<key>Comment</key>
@@ -3984,6 +4083,89 @@
<key>Value</key>
<string>Monospace</string>
</map>
+ <key>LuaAutorunPath</key>
+ <map>
+ <key>Comment</key>
+ <string>Directories containing scripts to autorun at viewer startup</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array>
+ <string>scripts/lua/auto</string>
+ </array>
+ </map>
+ <key>LuaChunk</key>
+ <map>
+ <key>Comment</key>
+ <string>Zero or more Lua chunks to run from command line</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array />
+ </map>
+ <key>LuaCommandPath</key>
+ <map>
+ <key>Comment</key>
+ <string>Directories containing scripts recognized as chat slash commands</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array>
+ <string>scripts/lua</string>
+ </array>
+ </map>
+ <key>LuaFeature</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewer's Lua script engine.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LuaRequirePath</key>
+ <map>
+ <key>Comment</key>
+ <string>Directories containing Lua modules loadable by require()</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array>
+ <string>scripts/lua/require</string>
+ </array>
+ </map>
+ <key>LuaScript</key>
+ <map>
+ <key>Comment</key>
+ <string>Zero or more Lua script files to run from command line</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array />
+ </map>
+ <key>LuaDebugShowSource</key>
+ <map>
+ <key>Comment</key>
+ <string>Show source info in Lua Debug Console output</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>GridStatusRSS</key>
<map>
<key>Comment</key>
@@ -4492,6 +4674,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>MapShowGridCoords</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/hides the grid coordinates of each region on the world map.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>MiniMapAutoCenter</key>
<map>
<key>Comment</key>
@@ -4514,17 +4707,17 @@
<key>Value</key>
<string />
</map>
- <key>MarketplaceListingsLogging</key>
- <map>
- <key>Comment</key>
- <string>Enable debug output associated with the Marketplace Listings (SLM) API.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
+ <key>MarketplaceListingsLogging</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable debug output associated with the Marketplace Listings (SLM) API.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>MarketplaceURL</key>
<map>
<key>Comment</key>
@@ -5421,28 +5614,28 @@
<key>Value</key>
<integer>1000</integer>
</map>
- <key>FakeInitialOutfitName</key>
- <map>
- <key>Comment</key>
- <string>Pretend that this is first time login and specified name was chosen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
+ <key>FakeInitialOutfitName</key>
+ <map>
+ <key>Comment</key>
+ <string>Pretend that this is first time login and specified name was chosen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
<string>String</string>
<key>Value</key>
<string />
- </map>
- <key>MyOutfitsAutofill</key>
- <map>
- <key>Comment</key>
- <string>Always autofill My Outfits from library when empty (else happens just once).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
+ </map>
+ <key>MyOutfitsAutofill</key>
+ <map>
+ <key>Comment</key>
+ <string>Always autofill My Outfits from library when empty (else happens just once).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>NearMeRange</key>
<map>
<key>Comment</key>
@@ -5551,7 +5744,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
- <integer>0</integer>
+ <integer>0</integer>
</map>
<key>NonvisibleObjectsInMemoryTime</key>
<map>
@@ -5562,7 +5755,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>64</integer>
+ <integer>64</integer>
</map>
<key>NoPreload</key>
<map>
@@ -6496,7 +6689,7 @@
<key>Value</key>
<real>6.0</real>
</map>
- <key>PreferredMaturity</key>
+ <key>PreferredMaturity</key>
<map>
<key>Comment</key>
<string>Setting for the user's preferred maturity level (consts in indra_constants.h)</string>
@@ -6505,7 +6698,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>13</integer>
+ <integer>13</integer>
</map>
<key>PreviewAmbientColor</key>
<map>
@@ -6675,8 +6868,8 @@
</map>
<key>PrimMediaMasterEnabled</key>
- <map>
- <key>Comment</key>
+ <map>
+ <key>Comment</key>
<string>Whether or not Media on a Prim is enabled.</string>
<key>Persist</key>
<integer>1</integer>
@@ -6685,9 +6878,9 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>PrimMediaControlsUseHoverControlSet</key>
- <map>
- <key>Comment</key>
+ <key>PrimMediaControlsUseHoverControlSet</key>
+ <map>
+ <key>Comment</key>
<string>Whether or not hovering over prim media uses minimal "hover" controls or the authored control set.</string>
<key>Persist</key>
<integer>1</integer>
@@ -6696,17 +6889,17 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>PrimMediaDragNDrop</key>
- <map>
- <key>Comment</key>
- <string>Enable drag and drop of URLs onto prim faces</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
+ <key>PrimMediaDragNDrop</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable drag and drop of URLs onto prim faces</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>PrimMediaMaxRetries</key>
<map>
<key>Comment</key>
@@ -6740,7 +6933,7 @@
<key>Value</key>
<real>5.0</real>
</map>
- <key>PrimMediaMaxSortedQueueSize</key>
+ <key>PrimMediaMaxSortedQueueSize</key>
<map>
<key>Comment</key>
<string>Maximum number of objects the viewer will load media for initially</string>
@@ -6751,7 +6944,7 @@
<key>Value</key>
<integer>100000</integer>
</map>
- <key>PrimMediaMaxRoundRobinQueueSize</key>
+ <key>PrimMediaMaxRoundRobinQueueSize</key>
<map>
<key>Comment</key>
<string>Maximum number of objects the viewer will continuously update media for</string>
@@ -7385,6 +7578,17 @@
<key>Value</key>
<integer>-1</integer>
</map>
+ <key>RenderBufferClearOnInvalidate</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to call glClear on render buffers that will be fully overwritten with new contents</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>RenderCompressTextures</key>
<map>
<key>Comment</key>
@@ -7893,6 +8097,28 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>RenderDebugTextureLabel</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable texture labels via glObjectLabel.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderDebugTextureLabelLocalFilesSession</key>
+ <map>
+ <key>Comment</key>
+ <string>Enumerate textures with local file names. Doesn't do anything until RenderDebugTextureLabel is set to true. Requires restart AND applies on the next session only.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>RenderDelayCreation</key>
<map>
<key>Comment</key>
@@ -8910,17 +9136,17 @@
<key>Value</key>
<integer>1024</integer>
</map>
- <key>RenderHeroProbeDistance</key>
- <map>
- <key>Comment</key>
- <string>Distance in meters for hero probes to render out to.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>8</real>
- </map>
+ <key>RenderHeroProbeDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance in meters for hero probes to render out to.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>8</real>
+ </map>
<key>RenderHeroProbeUpdateRate</key>
<map>
<key>Comment</key>
@@ -9485,17 +9711,17 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>RenderTransparentWater</key>
- <map>
- <key>Comment</key>
- <string>Render water as transparent. Setting to false renders water as opaque with a simple texture applied.</string>
+ <key>RenderTransparentWater</key>
+ <map>
+ <key>Comment</key>
+ <string>Render water as transparent. Setting to false renders water as opaque with a simple texture applied.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
- </map>
+ </map>
<key>RenderTreeLODFactor</key>
<map>
<key>Comment</key>
@@ -9799,18 +10025,18 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>RenderPreferStreamDraw</key>
- <map>
- <key>Comment</key>
- <string>Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderVolumeLODFactor</key>
+ <key>RenderPreferStreamDraw</key>
+ <map>
+ <key>Comment</key>
+ <string>Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderVolumeLODFactor</key>
<map>
<key>Comment</key>
<string>Controls level of detail of primitives (multiplier for current screen area when calculated level of detail)</string>
@@ -9942,18 +10168,95 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>ReportBugURL</key>
- <map>
- <key>Comment</key>
- <string>URL used for filing bugs from viewer</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>https://megapahit.com/enter_bug.cgi?product=Viewer</string>
- </map>
- <key>RevokePermsOnStopAnimation</key>
+ <key>ReportBugURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL used for filing bugs from viewer</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://megapahit.com/enter_bug.cgi?product=Viewer/</string>
+ </map>
+ <key>RestrainedLove</key>
+ <map>
+ <key>Comment</key>
+ <string>Toggles RLVa features (requires restart)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <boolean>0</boolean>
+ </map>
+ <key>RestrainedLoveDebug</key>
+ <map>
+ <key>Comment</key>
+ <string>Toggles RLVa debug mode (displays the commands when in debug mode)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <boolean>0</boolean>
+ </map>
+ <key>RLVaBlockedExperiences</key>
+ <map>
+ <key>Comment</key>
+ <string>List of experiences blocked from interacting with RLVa</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>bfe25fb4-222c-11e5-85a2-fa4c4ccaa202</string>
+ </map>
+ <key>RLVaDebugHideUnsetDuplicate</key>
+ <map>
+ <key>Comment</key>
+ <string>Suppresses reporting "unset" or "duplicate" command restrictions when RestrainedLoveDebug is TRUE</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <boolean>0</boolean>
+ </map>
+ <key>RLVaEnableTemporaryAttachments</key>
+ <map>
+ <key>Comment</key>
+ <string>Allows temporary attachments (regardless of origin) to issue RLV commands</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <boolean>1</boolean>
+ </map>
+ <key>RLVaExperimentalCommands</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables the experimental command set</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <boolean>1</boolean>
+ </map>
+ <key>RLVaTopLevelMenu</key>
+ <map>
+ <key>Comment</key>
+ <string>Show the RLVa specific menu as a top level menu</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <boolean>1</boolean>
+ </map>
+ <key>RevokePermsOnStopAnimation</key>
<map>
<key>Comment</key>
<string>Clear animation permssions when choosing "Stop Animating Me"</string>
@@ -10206,39 +10509,39 @@
<key>Value</key>
<real>400.0</real>
</map>
- <key>SceneLoadingMonitorEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enabled scene loading monitor if set</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SceneLoadingMonitorSampleTime</key>
- <map>
- <key>Comment</key>
- <string>Time between screen samples when monitor scene load (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
- <key>SceneLoadingMonitorPixelDiffThreshold</key>
- <map>
- <key>Comment</key>
- <string>Amount of pixels changed required to consider the scene as still loading (square root of fraction of pixels on screen)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.02</real>
- </map>
+ <key>SceneLoadingMonitorEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enabled scene loading monitor if set</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SceneLoadingMonitorSampleTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Time between screen samples when monitor scene load (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+ <key>SceneLoadingMonitorPixelDiffThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of pixels changed required to consider the scene as still loading (square root of fraction of pixels on screen)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.02</real>
+ </map>
<key>ScriptHelpFollowsCursor</key>
<map>
<key>Comment</key>
@@ -10415,7 +10718,7 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>AvatarNameTagMode</key>
+ <key>AvatarNameTagMode</key>
<map>
<key>Comment</key>
<string>Select Avatar Name Tag Mode</string>
@@ -10624,7 +10927,7 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>ShowScriptErrors</key>
+ <key>ShowScriptErrors</key>
<map>
<key>Comment</key>
<string>Show script errors</string>
@@ -10635,7 +10938,7 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>ShowScriptErrorsLocation</key>
+ <key>ShowScriptErrorsLocation</key>
<map>
<key>Comment</key>
<string>Show script error in chat (0) or window (1).</string>
@@ -10894,8 +11197,8 @@
<string>Display results of find events that are flagged as moderate</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -10907,8 +11210,8 @@
<string>Display results of find events that are flagged as adult</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -10920,8 +11223,8 @@
<string>Display results of find land sales that are flagged as general</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -10933,8 +11236,8 @@
<string>Display results of find land sales that are flagged as moderate</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -10946,8 +11249,8 @@
<string>Display results of find land sales that are flagged as adult</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -10959,8 +11262,8 @@
<string>Display results of find places or find popular that are in general sims</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -10972,8 +11275,8 @@
<string>Display results of find places or find popular that are in moderate sims</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -10985,8 +11288,8 @@
<string>Display results of find places or find popular that are in adult sims</string>
<key>Persist</key>
<integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -11124,17 +11427,17 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>ShowTutorial</key>
- <map>
- <key>Comment</key>
- <string>Show tutorial window on login</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
+ <key>ShowTutorial</key>
+ <map>
+ <key>Comment</key>
+ <string>Show tutorial window on login</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>ShowVoiceVisualizersInCalls</key>
<map>
<key>Comment</key>
@@ -12840,9 +13143,9 @@
<key>Use24HourClock</key>
<map>
<key>Comment</key>
- <string>12 vs 24. At the moment only for region restart schedule floater</string>
+ <string>12 vs 24. At the moment coverage is partial</string>
<key>Persist</key>
- <integer>0</integer>
+ <integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -13796,17 +14099,17 @@
<key>Value</key>
<real>0.40000000596</real>
</map>
- <key>moapbeacon</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight media on a prim sources</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
+ <key>moapbeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight media on a prim sources</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>particlesbeacon</key>
<map>
<key>Comment</key>
@@ -13906,17 +14209,17 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>SLURLDragNDrop</key>
- <map>
- <key>Comment</key>
- <string>Enable drag and drop of SLURLs onto the viewer</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
+ <key>SLURLDragNDrop</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable drag and drop of SLURLs onto the viewer</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>SLURLPassToOtherInstance</key>
<map>
<key>Comment</key>
@@ -14432,10 +14735,10 @@
<string>LLSD</string>
<key>Value</key>
<array>
- <string>snapshot</string>
- <string>postcard</string>
- <string>mini_map</string>
- <string>beacons</string>
+ <string>snapshot</string>
+ <string>postcard</string>
+ <string>mini_map</string>
+ <string>beacons</string>
</array>
</map>
<key>LandmarksSortedByDate</key>
@@ -14449,10 +14752,32 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>OutfitGallerySortByName</key>
+ <key>OutfitGallerySortOrder</key>
<map>
<key>Comment</key>
- <string>Always sort outfits by name in Outfit Gallery</string>
+ <string>Gallery sorting: 0 - sort outfits by name, 1 - images frst, 2 - favorites first</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OutfitListSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>How outfit list in Avatar's floater is sorted. 0 - by name 1 - favorites to top</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OutfitListFilterFullList</key>
+ <map>
+ <key>Comment</key>
+ <string> 0 - show only matches. 1 - show all items in outfit as long as outfit or item inside matches.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -15196,7 +15521,7 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>LocalTerrainAsset1</key>
+ <key>LocalTerrainAsset1</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
@@ -15207,7 +15532,7 @@
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
- <key>LocalTerrainAsset2</key>
+ <key>LocalTerrainAsset2</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
@@ -15218,7 +15543,7 @@
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
- <key>LocalTerrainAsset3</key>
+ <key>LocalTerrainAsset3</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
@@ -15229,7 +15554,7 @@
<key>Value</key>
<string>00000000-0000-0000-0000-000000000000</string>
</map>
- <key>LocalTerrainAsset4</key>
+ <key>LocalTerrainAsset4</key>
<map>
<key>Comment</key>
<string>If set to a non-null UUID, overrides the terrain asset locally for all regions with material assets. Local terrain assets are not visible to others. Please keep in mind that this debug setting may be temporary. Do not rely on this setting existing in future viewer builds.</string>
@@ -15480,7 +15805,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>5</integer>
+ <integer>8</integer>
</map>
<key>TerrainPaintResolution</key>
<map>
@@ -15493,7 +15818,7 @@
<key>Value</key>
<integer>2048</integer>
</map>
- <key>PathfindingRetrieveNeighboringRegion</key>
+ <key>PathfindingRetrieveNeighboringRegion</key>
<map>
<key>Comment</key>
<string>Download a neighboring region when visualizing a pathfinding navmesh (default val 99 means do not download neighbors).</string>
@@ -15502,9 +15827,9 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>99</integer>
+ <integer>99</integer>
</map>
- <key>PathfindingNavMeshClear</key>
+ <key>PathfindingNavMeshClear</key>
<map>
<key>Comment</key>
<string>Background color when displaying pathfinding navmesh.</string>
@@ -15664,7 +15989,7 @@
<real>1.0</real>
</array>
</map>
- <key>PathfindingTestPathValidEndColor</key>
+ <key>PathfindingTestPathValidEndColor</key>
<map>
<key>Comment</key>
<string>Color of the pathfinding test-pathing tool end-point when the path is valid.</string>
@@ -15696,7 +16021,7 @@
<real>1.0</real>
</array>
</map>
- <key>PathfindingTestPathColor</key>
+ <key>PathfindingTestPathColor</key>
<map>
<key>Comment</key>
<string>Color of the pathfinding test-path when the path is valid.</string>
@@ -16333,6 +16658,50 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>InventoryFavoritesUseStar</key>
+ <map>
+ <key>Comment</key>
+ <string>Show star near favorited items in inventory</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>InventoryFavoritesUseHollowStar</key>
+ <map>
+ <key>Comment</key>
+ <string>Show star near folders that contain favorites</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>InventoryFavoritesColorText</key>
+ <map>
+ <key>Comment</key>
+ <string>render favorite items using InventoryFavoriteText as color</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>InventoryAddAttachmentBehavior</key>
+ <map>
+ <key>Comment</key>
+ <string>Defines behavior when hitting return on an inventory item</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>StatsReportMaxDuration</key>
<map>
<key>Comment</key>
@@ -16344,17 +16713,17 @@
<key>Value</key>
<real>300</real>
</map>
- <key>StatsReportFileInterval</key>
- <map>
- <key>Comment</key>
- <string>Interval to save viewer stats file data</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.2</real>
- </map>
+ <key>StatsReportFileInterval</key>
+ <map>
+ <key>Comment</key>
+ <string>Interval to save viewer stats file data</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.2</real>
+ </map>
<key>StatsReportSkipZeroDataSaves</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index 80a4bec57f..8361a50b6c 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -329,7 +329,7 @@
<key>KeepConversationLogTranscripts</key>
<map>
<key>Comment</key>
- <string>Keep a conversation log and transcripts</string>
+ <string>Keep a conversation log and transcripts 2 - both, 1 - logs, 0 - none</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index 23a3ca4911..41ff2913e9 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -30,7 +30,6 @@ out vec4 frag_color;
uniform sampler2D lightMap;
uniform float dist_factor;
-uniform float blur_size;
uniform vec2 delta;
uniform vec2 screen_res;
uniform vec3 kern[4];
diff --git a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl
index 0a0fa0a374..4a26b8924a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl
@@ -30,8 +30,6 @@ out vec4 frag_color;
uniform sampler2D diffuseRect;
uniform sampler2D depthMap;
-uniform float depth_cutoff;
-uniform float norm_cutoff;
uniform float focal_distance;
uniform float blur_constant;
uniform float tan_pixel_angle;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl
index 6791fe44d9..e77e972873 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/screenSpaceReflUtil.glsl
@@ -25,7 +25,7 @@
// debug stub
-float random (vec2 uv)
+float random (vec2 uv)
{
return 0.f;
}
diff --git a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl
index cf20653a0f..a79a56d725 100644
--- a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl
@@ -1,5 +1,5 @@
/**
- * @file terrainBakeF.glsl
+ * @file pbrTerrainBakeF.glsl
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
diff --git a/indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl b/indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl
new file mode 100644
index 0000000000..e79e9010e6
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/terrainStampF.glsl
@@ -0,0 +1,44 @@
+/**
+ * @file terrainStampF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+/*[EXTRA_CODE_HERE]*/
+
+out vec4 frag_color;
+
+// Paint texture to stamp into the "paintmap"
+uniform sampler2D diffuseMap;
+
+in vec2 vary_texcoord0;
+
+void main()
+{
+ vec4 col = texture(diffuseMap, vary_texcoord0);
+ if (col.a <= 0.0f)
+ {
+ discard;
+ }
+
+ frag_color = max(col, vec4(0));
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl b/indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl
new file mode 100644
index 0000000000..294fa6be26
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/terrainStampV.glsl
@@ -0,0 +1,39 @@
+/**
+ * @file terrainStampV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 modelview_projection_matrix;
+uniform vec2 terrain_stamp_scale;
+
+in vec3 position;
+
+out vec2 vary_texcoord0;
+
+void main()
+{
+ gl_Position = modelview_projection_matrix * vec4(position, 1.0);
+ // Positions without transforms are treated as UVs for the purpose of this shader.
+ vary_texcoord0.xy = terrain_stamp_scale * position.xy;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl
index 35848ff4cd..4fb24ca0b1 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl
@@ -37,7 +37,7 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear)
{
ambenv = vec3(reflection_probe_ambiance * 0.25);
-
+
vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
vec3 env_vec = env_mat * refnormpersp;
glossenv = srgb_to_linear(texture(environmentMap, env_vec).rgb);
@@ -59,7 +59,7 @@ void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 l
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit_linear)
{
ambenv = vec3(reflection_probe_ambiance * 0.25);
-
+
vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
vec3 env_vec = env_mat * refnormpersp;
@@ -70,7 +70,7 @@ void sampleReflectionProbesLegacy(out vec3 ambenv, out vec3 glossenv, out vec3 l
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)
{
-
+
}
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity)
diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
index 4ed778371f..809ad2f0bd 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
@@ -33,7 +33,6 @@ uniform sampler2D emissiveRect; // PBR linear packed Occlusion, Roughness, Metal
uniform sampler2D lightFunc;
uniform vec3 env_mat[3];
-uniform float sun_wash;
uniform int light_count;
uniform vec4 light[LIGHT_COUNT]; // .w = size; see C++ fullscreen_lights.push_back()
uniform vec4 light_col[LIGHT_COUNT]; // .a = falloff
diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
index 6c13757149..41a19ea1b6 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
@@ -33,7 +33,6 @@ uniform sampler2D emissiveRect; // PBR linear packed Occlusion, Roughness, Metal
uniform sampler2D lightFunc;
uniform vec3 env_mat[3];
-uniform float sun_wash;
// light params
uniform vec3 color;
@@ -46,7 +45,6 @@ in vec3 trans_center;
uniform vec2 screen_res;
uniform mat4 inv_proj;
-uniform vec4 viewport;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index 4231d8580e..a34e97c171 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -39,9 +39,6 @@ uniform sampler2D lightMap;
uniform sampler2D lightFunc;
-uniform float blur_size;
-uniform float blur_fidelity;
-
#if defined(HAS_SSAO)
uniform float ssao_irradiance_scale;
uniform float ssao_irradiance_max;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
index bc4d36d10d..e99aa5ace4 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
@@ -47,7 +47,6 @@ uniform float near_clip;
uniform float far_clip;
uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
-uniform float sun_wash;
uniform int proj_shadow_idx;
uniform float shadow_fade;
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index 6f7f553cec..dc5d1ff6c4 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -28,27 +28,27 @@ version 29
//
list all
RenderAnisotropic 1 1
-RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
RenderAvatarPhysicsLODFactor 1 1.0
RenderAvatarMaxNonImpostors 1 16
RenderAvatarMaxComplexity 1 350000
RenderAutoMuteSurfaceAreaLimit 1 1000.0
RenderCubeMap 1 1
-RenderDelayVBUpdate 1 0
RenderFarClip 1 256
RenderFlexTimeFactor 1 1.0
RenderFogRatio 1 4.0
RenderGamma 1 0
RenderGlowResolutionPow 1 9
-RenderGround 1 1
RenderMaxPartCount 1 8192
RenderObjectBump 1 1
-RenderLocalLights 1 1
-RenderReflectionDetail 1 4
+RenderLocalLightCount 1 4096
+RenderTransparentWater 1 1
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 2
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
-RenderTransparentWater 1 1
+RenderTerrainPBRDetail 1 0
+RenderTerrainPBRPlanarSampleCount 1 3
RenderTreeLODFactor 1 1.0
RenderVBOEnable 1 1
RenderVBOMappingDisable 1 1
@@ -61,48 +61,26 @@ Disregard128DefaultDrawDistance 1 1
Disregard96DefaultDrawDistance 1 1
RenderCompressTextures 1 1
RenderShaderLightingMaxLevel 1 3
+RenderReflectionProbeLevel 1 3
RenderDeferred 1 1
RenderDeferredSSAO 1 1
-RenderUseAdvancedAtmospherics 1 0
RenderShadowDetail 1 2
-RenderFSAASamples 1 16
+RenderUseStreamVBO 1 1
+RenderFSAAType 1 2
+RenderFSAASamples 1 3
RenderMaxTextureIndex 1 16
+RenderGLContextCoreProfile 1 1
+RenderGLMultiThreadedTextures 1 0
+RenderGLMultiThreadedMedia 1 0
+RenderReflectionProbeResolution 1 128
+RenderScreenSpaceReflections 1 1
RenderMirrors 1 1
-
-//
-// Low Graphics Settings (fixed function)
-//
-list LowFixedFunction
-RenderAnisotropic 1 0
-RenderAvatarCloth 1 0
-RenderAvatarLODFactor 1 0
-RenderAvatarPhysicsLODFactor 1 0
-RenderAvatarMaxNonImpostors 1 3
-RenderAvatarMaxComplexity 1 25000
-RenderFarClip 1 64
-RenderFlexTimeFactor 1 0
-RenderGlowResolutionPow 1 8
-RenderLocalLights 1 0
-RenderMaxPartCount 1 0
-RenderObjectBump 1 0
-RenderReflectionDetail 1 0
-RenderTerrainDetail 1 0
-RenderTerrainLODFactor 1 1
-RenderTransparentWater 1 0
-RenderTreeLODFactor 1 0
-RenderVolumeLODFactor 1 1.125
-WindLightUseAtmosShaders 1 0
-RenderDeferred 1 0
-RenderDeferredSSAO 1 0
-RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail 1 0
-WLSkyDetail 1 48
-RenderFSAASamples 1 0
-RenderMirrors 1 0
-RenderHeroProbeResolution 1 256
-RenderHeroProbeDistance 1 4
-RenderHeroProbeUpdateRate 1 6
+RenderHeroProbeResolution 1 2048
+RenderHeroProbeDistance 1 16
+RenderHeroProbeUpdateRate 1 4
RenderHeroProbeConservativeUpdateMultiplier 1 16
+RenderDownScaleMethod 1 1
+RenderCASSharpness 1 1
//
@@ -110,7 +88,6 @@ RenderHeroProbeConservativeUpdateMultiplier 1 16
//
list Low
RenderAnisotropic 1 0
-RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0
RenderAvatarPhysicsLODFactor 1 0
RenderAvatarMaxNonImpostors 1 3
@@ -118,276 +95,260 @@ RenderAvatarMaxComplexity 1 35000
RenderFarClip 1 64
RenderFlexTimeFactor 1 0
RenderGlowResolutionPow 1 8
-RenderLocalLights 1 0
+RenderLocalLightCount 1 8
RenderMaxPartCount 1 0
-RenderObjectBump 1 0
-RenderReflectionDetail 1 0
+RenderTransparentWater 1 0
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 0
RenderTerrainDetail 1 0
RenderTerrainLODFactor 1 1
-RenderTransparentWater 1 0
+RenderTerrainPBRDetail 1 -4
+RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0
RenderVolumeLODFactor 1 1.125
-WindLightUseAtmosShaders 1 0
-RenderDeferred 1 0
RenderDeferredSSAO 1 0
-RenderUseAdvancedAtmospherics 1 0
RenderShadowDetail 1 0
-WLSkyDetail 1 48
+WLSkyDetail 1 96
+RenderFSAAType 1 0
RenderFSAASamples 1 0
+RenderScreenSpaceReflections 1 0
+RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 4
-RenderHeroProbeUpdateRate 1 6
+RenderHeroProbeUpdateRate 1 6
RenderHeroProbeConservativeUpdateMultiplier 1 16
+RenderCASSharpness 1 0
//
// Medium Low Graphics Settings
//
list LowMid
RenderAnisotropic 1 0
-RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 0.5
RenderAvatarMaxComplexity 1 100000
RenderAvatarPhysicsLODFactor 1 0.75
+RenderAvatarMaxNonImpostors 1 5
RenderFarClip 1 96
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 8
RenderMaxPartCount 1 2048
-RenderObjectBump 1 1
-RenderLocalLights 1 1
-RenderReflectionDetail 1 0
+RenderLocalLightCount 1 256
+RenderTransparentWater 1 0
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 1.0
-RenderTransparentWater 1 1
+RenderTerrainPBRDetail 1 -1
+RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0.5
RenderVolumeLODFactor 1 1.125
-WindLightUseAtmosShaders 1 0
-RenderDeferred 1 0
RenderDeferredSSAO 1 0
-RenderUseAdvancedAtmospherics 1 0
RenderShadowDetail 1 0
-WLSkyDetail 1 48
+WLSkyDetail 1 96
+RenderFSAAType 1 0
RenderFSAASamples 1 0
+RenderScreenSpaceReflections 1 0
+RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
+RenderCASSharpness 1 0
//
// Medium Graphics Settings (standard)
//
list Mid
RenderAnisotropic 1 1
-RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
RenderAvatarMaxComplexity 1 200000
RenderAvatarPhysicsLODFactor 1 1.0
+RenderAvatarMaxNonImpostors 1 7
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderObjectBump 1 1
-RenderLocalLights 1 1
-RenderReflectionDetail 1 0
+RenderLocalLightCount 1 512
+RenderTransparentWater 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
-RenderTransparentWater 1 1
+RenderTerrainPBRDetail 1 0
+RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0.5
-RenderVolumeLODFactor 1 1.125
-WindLightUseAtmosShaders 1 1
-RenderDeferred 1 0
+RenderVolumeLODFactor 1 1.25
RenderDeferredSSAO 1 0
-RenderUseAdvancedAtmospherics 1 0
RenderShadowDetail 1 0
-WLSkyDetail 1 48
-RenderFSAASamples 1 2
+WLSkyDetail 1 96
+RenderFSAAType 1 1
+RenderFSAASamples 1 1
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 0
+RenderScreenSpaceReflections 1 0
+RenderReflectionProbeLevel 1 1
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 3
RenderHeroProbeConservativeUpdateMultiplier 1 16
+RenderCASSharpness 1 0
//
-// Medium High Graphics Settings (deferred enabled)
+// Medium High Graphics Settings
//
list MidHigh
RenderAnisotropic 1 1
-RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
RenderAvatarMaxComplexity 1 250000
RenderAvatarPhysicsLODFactor 1 1.0
+RenderAvatarMaxNonImpostors 1 9
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderObjectBump 1 1
-RenderLocalLights 1 1
-RenderReflectionDetail 1 0
+RenderLocalLightCount 1 1024
+RenderTransparentWater 1 0
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
-RenderTransparentWater 1 1
+RenderTerrainPBRDetail 1 0
+RenderTerrainPBRPlanarSampleCount 1 1
RenderTreeLODFactor 1 0.5
-RenderVolumeLODFactor 1 1.125
-WindLightUseAtmosShaders 1 1
-RenderDeferred 1 1
-RenderUseAdvancedAtmospherics 1 0
+RenderVolumeLODFactor 1 1.375
RenderDeferredSSAO 1 0
RenderShadowDetail 1 0
-WLSkyDetail 1 48
-RenderFSAASamples 1 2
+WLSkyDetail 1 96
+RenderFSAAType 1 1
+RenderFSAASamples 1 1
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 1
+RenderScreenSpaceReflections 1 0
+RenderReflectionProbeLevel 1 2
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
+RenderCASSharpness 1 0
//
-// High Graphics Settings (deferred + SSAO)
+// High Graphics Settings (SSAO + sun shadows)
//
list High
RenderAnisotropic 1 1
-RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
RenderAvatarMaxComplexity 1 300000
RenderAvatarPhysicsLODFactor 1 1.0
+RenderAvatarMaxNonImpostors 1 11
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderObjectBump 1 1
-RenderLocalLights 1 1
-RenderReflectionDetail 1 0
+RenderLocalLightCount 1 2048
+RenderTransparentWater 1 1
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
-RenderTransparentWater 1 1
+RenderTerrainPBRDetail 1 0
+RenderTerrainPBRPlanarSampleCount 1 3
RenderTreeLODFactor 1 0.5
-RenderVolumeLODFactor 1 1.125
-WindLightUseAtmosShaders 1 1
-RenderDeferred 1 1
+RenderVolumeLODFactor 1 1.5
RenderDeferredSSAO 1 1
-RenderUseAdvancedAtmospherics 1 0
-RenderShadowDetail 1 0
-WLSkyDetail 1 48
+RenderShadowDetail 1 1
+WLSkyDetail 1 96
+RenderFSAAType 1 2
RenderFSAASamples 1 2
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 1
+RenderScreenSpaceReflections 1 0
+RenderReflectionProbeLevel 1 3
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 8
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
+RenderCASSharpness 1 0.4
//
-// High Ultra Graphics Settings (deferred + SSAO + shadows)
+// High Ultra Graphics Settings (deferred + SSAO + all shadows)
//
list HighUltra
RenderAnisotropic 1 1
-RenderAvatarCloth 1 0
RenderAvatarLODFactor 1 1.0
RenderAvatarMaxComplexity 1 350000
RenderAvatarPhysicsLODFactor 1 1.0
+RenderAvatarMaxNonImpostors 1 16
RenderFarClip 1 128
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
RenderMaxPartCount 1 4096
-RenderObjectBump 1 1
-RenderLocalLights 1 1
-RenderReflectionDetail 1 0
+RenderLocalLightCount 1 4096
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTerrainPBRDetail 1 0
+RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 0.5
-RenderVolumeLODFactor 1 1.125
-WindLightUseAtmosShaders 1 1
-RenderDeferred 1 1
+RenderVolumeLODFactor 1 1.75
RenderDeferredSSAO 1 1
-RenderUseAdvancedAtmospherics 1 0
RenderShadowDetail 1 2
-WLSkyDetail 1 48
+WLSkyDetail 1 96
+RenderFSAAType 1 2
RenderFSAASamples 1 2
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 1
+RenderScreenSpaceReflections 1 0
+RenderReflectionProbeLevel 1 3
RenderMirrors 1 0
-RenderHeroProbeResolution 1 512
+RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
+RenderCASSharpness 1 0.4
//
// Ultra graphics (REALLY PURTY!)
//
list Ultra
RenderAnisotropic 1 1
-RenderAvatarCloth 1 1
RenderAvatarLODFactor 1 1.0
+RenderAvatarMaxNonImpostors 1 16
RenderAvatarPhysicsLODFactor 1 1.0
RenderFarClip 1 256
RenderFlexTimeFactor 1 1.0
RenderGlowResolutionPow 1 9
-RenderLocalLights 1 1
+RenderLocalLightCount 1 8192
RenderMaxPartCount 1 8192
-RenderObjectBump 1 1
-RenderReflectionDetail 1 4
RenderTerrainDetail 1 1
RenderTerrainLODFactor 1 2.0
+RenderTerrainPBRDetail 1 0
+RenderTerrainPBRPlanarSampleCount 1 3
RenderTransparentWater 1 1
RenderTreeLODFactor 1 1.0
RenderVolumeLODFactor 1 2.0
WindLightUseAtmosShaders 1 1
WLSkyDetail 1 128
-RenderDeferred 1 1
RenderDeferredSSAO 1 1
-RenderUseAdvancedAtmospherics 1 0
RenderShadowDetail 1 2
-RenderFSAASamples 1 2
+RenderFSAAType 1 2
+RenderFSAASamples 1 3
+RenderReflectionsEnabled 1 1
+RenderReflectionProbeDetail 1 1
+RenderScreenSpaceReflections 1 0
+RenderReflectionProbeLevel 1 3
RenderMirrors 1 0
-RenderHeroProbeResolution 1 1024
+RenderHeroProbeResolution 1 2048
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
+RenderCASSharpness 1 0.4
//
// Class Unknown Hardware (unknown)
//
list Unknown
-RenderVBOEnable 1 0
RenderShadowDetail 1 0
-RenderDeferred 1 0
RenderDeferredSSAO 1 0
-RenderUseAdvancedAtmospherics 1 0
-
-//
-// Class 0 Hardware (just old)
-//
-list Class0
-RenderVBOEnable 1 1
-
-//
-// Class 1 Hardware
-//
-list Class1
-RenderVBOEnable 1 1
-
-//
-// Class 2 Hardware
-//
-list Class2
-RenderVBOEnable 1 1
-
-//
-// Class 3 Hardware
-//
-list Class3
-RenderVBOEnable 1 1
-
-//
-// Class 4 Hardware
-//
-list Class4
-RenderVBOEnable 1 1
-
-//
-// Class 5 Hardware
-//
-list Class5
-RenderVBOEnable 1 1
+RenderMirrors 1 0
//
// VRAM > 512MB
@@ -396,339 +357,41 @@ list VRAMGT512
RenderCompressTextures 1 0
//
-// No Pixel Shaders available
-//
-list NoPixelShaders
-RenderAvatarCloth 0 0
-RenderReflectionDetail 0 0
-WindLightUseAtmosShaders 0 0
-RenderDeferred 0 0
-RenderDeferredSSAO 0 0
-RenderUseAdvancedAtmospherics 0 0
-RenderShadowDetail 0 0
-
-//
-// No Vertex Shaders available
-//
-list NoVertexShaders
-RenderAvatarCloth 0 0
-RenderReflectionDetail 0 0
-WindLightUseAtmosShaders 0 0
-RenderDeferred 0 0
-RenderDeferredSSAO 0 0
-RenderUseAdvancedAtmospherics 0 0
-RenderShadowDetail 0 0
-
-//
-// GL_ARB_map_buffer_range exists
-//
-list MapBufferRange
-RenderVBOMappingDisable 1 1
-
-
-//
// "Default" setups for safe, low, medium, high
//
list safe
RenderAnisotropic 1 0
-RenderAvatarCloth 0 0
RenderAvatarMaxNonImpostors 1 16
RenderAvatarMaxComplexity 1 80000
-RenderObjectBump 0 0
-RenderLocalLights 1 0
+RenderLocalLightCount 1 0
RenderMaxPartCount 1 1024
RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-RenderReflectionDetail 0 0
-WindLightUseAtmosShaders 0 0
-RenderDeferred 0 0
+RenderTransparentWater 1 0
RenderDeferredSSAO 0 0
-RenderUseAdvancedAtmospherics 0 0
RenderShadowDetail 0 0
-
-//
-// CPU based feature masks
-//
-
-// 1Ghz or less (equiv)
-list CPUSlow
-RenderMaxPartCount 1 1024
-
-//
-// RAM based feature masks
-//
-list RAM256MB
-RenderObjectBump 0 0
-
-//
-// Graphics card based feature masks
-//
-list OpenGLPre15
-RenderVBOEnable 1 0
-
-list OpenGLPre30
-RenderDeferred 0 0
-RenderMaxTextureIndex 1 1
+RenderReflectionProbeDetail 0 -1
+RenderMirrors 0 0
list Intel
RenderAnisotropic 1 0
-// Avoid some Intel crashes on Linux
-RenderCubeMap 0 0
+RenderFSAAType 1 0
RenderFSAASamples 1 0
+RenderGLContextCoreProfile 1 0
+RenderGLMultiThreadedMedia 1 0
+RenderDownScaleMethod 1 0
-list GeForce2
-RenderAnisotropic 1 0
-RenderMaxPartCount 1 2048
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 1
-
-list SiS
-UseOcclusion 0 0
-
-
-list Intel_830M
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_845G
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_855GM
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_865G
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_900
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_915GM
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_915G
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_945GM
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_945G
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_950
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_965
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-UseOcclusion 0 0
-
-list Intel_G33
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_Bear_Lake
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_Broadwater
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_Brookdale
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_Montara
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-list Intel_Springdale
-RenderTerrainDetail 1 0
-RenderVBOEnable 1 0
-
-
-list ATI_FireGL_5200
-RenderVBOEnable 1 0
-WindLightUseAtmosShaders 0 0
-
-
-list ATI_Mobility_Radeon_7xxx
-RenderVBOEnable 0 0
-
-list ATI_Radeon_7xxx
-RenderVBOEnable 0 0
-
-list ATI_All-in-Wonder_Radeon
-RenderVBOEnable 0 0
-
-list ATI_All-in-Wonder_7500
-RenderVBOEnable 0 0
-
-list ATI_Mobility_Radeon_9600
-Disregard96DefaultDrawDistance 1 0
-
-
-/// tweaked ATI to 96 Draw distance
-
-list ATI_Radeon_9000
-Disregard96DefaultDrawDistance 1 0
-list ATI_Radeon_9200
-Disregard96DefaultDrawDistance 1 0
-list ATI_Radeon_9500
-Disregard96DefaultDrawDistance 1 0
-list ATI_Radeon_9600
-Disregard96DefaultDrawDistance 1 0
-
-/// tweaked ATI to 128 draw distance
-
-list ATI_Radeon_X300
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_X400
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_X500
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_X600
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_X700
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_X1300
-Disregard128DefaultDrawDistance 1 0
-UseStartScreen 0 0
-list ATI_Radeon_X1400
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_X1500
-Disregard128DefaultDrawDistance 1 0
-UseStartScreen 0 0
-list ATI_Radeon_X1600
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_X1700
-Disregard128DefaultDrawDistance 1 0
-list ATI_Mobility_Radeon_X1xxx
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_HD_2300
-Disregard128DefaultDrawDistance 1 0
-list ATI_Radeon_HD_2400
-Disregard128DefaultDrawDistance 1 0
-list ATI_ASUS_AH24xx
-Disregard128DefaultDrawDistance 1 0
-
-
-// Avatar hardware skinning causes invisible avatars
-// on various ATI chipsets on drivers before 8.2
-
-list ATIOldDriver
-RenderAvatarCloth 0 0
-// Avoid driver crashes with some features on Linux with old ATI drivers
-UseOcclusion 0 0
-WindLightUseAtmosShaders 0 0
-
-
-/// Tweaked NVIDIA
-
-list NVIDIA_GeForce_FX_5100
-Disregard96DefaultDrawDistance 1 0
-list NVIDIA_GeForce_FX_5200
-Disregard96DefaultDrawDistance 1 0
-list NVIDIA_GeForce_FX_5500
-Disregard96DefaultDrawDistance 1 0
-list NVIDIA_GeForce_FX_5600
-Disregard96DefaultDrawDistance 1 0
-
-list NVIDIA_GeForce_FX_Go5100
-Disregard96DefaultDrawDistance 1 0
-list NVIDIA_GeForce_FX_Go5200
-Disregard96DefaultDrawDistance 1 0
-list NVIDIA_GeForce_FX_Go5300
-Disregard96DefaultDrawDistance 1 0
-list NVIDIA_GeForce_FX_Go5500
-Disregard96DefaultDrawDistance 1 0
-list NVIDIA_GeForce_FX_Go5600
-Disregard96DefaultDrawDistance 1 0
-
-list NVIDIA_GeForce_6100
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_6200
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_6500
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_6600
-Disregard128DefaultDrawDistance 1 0
-
-list NVIDIA_G73
-Disregard128DefaultDrawDistance 1 0
-
-list NVIDIA_GeForce_Go_6100
-RenderVBOEnable 1 0
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_Go_6200
-RenderVBOEnable 1 0
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_Go_6500
-RenderVBOEnable 1 0
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_Go_6600
-RenderVBOEnable 1 0
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_Go_6700
-RenderVBOEnable 1 0
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_Go_6800
-RenderVBOEnable 1 0
-Disregard128DefaultDrawDistance 1 0
-list NVIDIA_GeForce_Go_6
-RenderVBOEnable 1 0
-Disregard128DefaultDrawDistance 1 0
+list AMD
+RenderGLMultiThreadedTextures 1 0
-list NVIDIA_GeForce_7000
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7100
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7200
-Disregard128DefaultDrawDistance 1 0
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7300
-Disregard128DefaultDrawDistance 1 0
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7400
-Disregard128DefaultDrawDistance 1 0
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7500
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7600
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7700
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7800
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_7900
-RenderShaderLightingMaxLevel 1 2
+list NVIDIA
+RenderGLMultiThreadedMedia 1 1
-list NVIDIA_GeForce_Go_7200
-Disregard128DefaultDrawDistance 1 0
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_Go_7300
-Disregard128DefaultDrawDistance 1 0
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_Go_7300_LE
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_Go_7400
-Disregard128DefaultDrawDistance 1 0
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_Go_7600
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_Go_7700
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_Go_7800
-RenderShaderLightingMaxLevel 1 2
-list NVIDIA_GeForce_Go_7900
-RenderShaderLightingMaxLevel 1 2
+list GL3
+RenderFSAAType 0 0
+RenderFSAASamples 0 0
+RenderReflectionsEnabled 0 0
+RenderReflectionProbeDetail 0 0
+RenderMirrors 0 0
+list TexUnit16orLess
+RenderTerrainPBRDetail 1 -1
diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp
index f362fa51cb..55482166e9 100644
--- a/indra/newview/gltfscenemanager.cpp
+++ b/indra/newview/gltfscenemanager.cpp
@@ -213,6 +213,7 @@ void GLTFSceneManager::uploadSelection()
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
+ LLUUID::null,
false,
finish,
failure));
@@ -276,6 +277,7 @@ void GLTFSceneManager::uploadSelection()
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
+ LLUUID::null,
false,
finish,
failure));
@@ -500,7 +502,7 @@ void GLTFSceneManager::update()
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, buffer](LLUUID assetId, LLSD response)
{
LLAppViewer::instance()->postToMainCoro(
- [=]()
+ [=, this]()
{
if (mUploadingAsset)
{
@@ -545,6 +547,7 @@ void GLTFSceneManager::update()
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
+ LLUUID::null,
false,
finish,
failure));
diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp
index 43507f13e9..e48cbe824a 100644
--- a/indra/newview/groupchatlistener.cpp
+++ b/indra/newview/groupchatlistener.cpp
@@ -2,11 +2,11 @@
* @file groupchatlistener.cpp
* @author Nat Goodspeed
* @date 2011-04-11
- * @brief Implementation for groupchatlistener.
+ * @brief Implementation for LLGroupChatListener.
*
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
+ * Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,43 +34,82 @@
// std headers
// external library headers
// other Linden headers
+#include "llchat.h"
#include "llgroupactions.h"
#include "llimview.h"
+static const F64 GROUP_CHAT_THROTTLE_PERIOD = 1.f;
-namespace {
- void startIm_wrapper(LLSD const & event)
+LLGroupChatListener::LLGroupChatListener():
+ LLEventAPI("GroupChat",
+ "API to enter, leave, send and intercept group chat messages"),
+ mIMThrottle("sendGroupIM", &LLGroupChatListener::sendGroupIM_, this,
+ GROUP_CHAT_THROTTLE_PERIOD)
+{
+ add("startGroupChat",
+ "Enter a group chat in group with UUID [\"group_id\"]\n"
+ "Assumes the logged-in agent is already a member of this group.",
+ &LLGroupChatListener::startGroupChat,
+ llsd::map("group_id", LLSD()));
+ add("leaveGroupChat",
+ "Leave a group chat in group with UUID [\"group_id\"]\n"
+ "Assumes a prior successful startIM request.",
+ &LLGroupChatListener::leaveGroupChat,
+ llsd::map("group_id", LLSD()));
+ add("sendGroupIM",
+ "send a [\"message\"] to group with UUID [\"group_id\"]",
+ &LLGroupChatListener::sendGroupIM,
+ llsd::map("message", LLSD(), "group_id", LLSD()));
+}
+
+bool is_in_group(LLEventAPI::Response &response, const LLSD &data)
+{
+ if (!LLGroupActions::isInGroup(data["group_id"]))
{
- LLUUID session_id = LLGroupActions::startIM(event["id"].asUUID());
- sendReply(LLSDMap("session_id", LLSD(session_id)), event);
+ response.error(stringize("You are not the member of the group:", std::quoted(data["group_id"].asString())));
+ return false;
}
+ return true;
+}
- void send_message_wrapper(const std::string& text, const LLUUID& session_id, const LLUUID& group_id)
+void LLGroupChatListener::startGroupChat(LLSD const &data)
+{
+ Response response(LLSD(), data);
+ if (!is_in_group(response, data))
+ {
+ return;
+ }
+ if (LLGroupActions::startIM(data["group_id"]).isNull())
{
- LLIMModel::sendMessage(text, session_id, group_id, IM_SESSION_GROUP_START);
+ return response.error(stringize("Failed to start group chat session ", std::quoted(data["group_id"].asString())));
}
}
+void LLGroupChatListener::leaveGroupChat(LLSD const &data)
+{
+ Response response(LLSD(), data);
+ if (is_in_group(response, data))
+ {
+ LLGroupActions::endIM(data["group_id"].asUUID());
+ }
+}
-GroupChatListener::GroupChatListener():
- LLEventAPI("GroupChat",
- "API to enter, leave, send and intercept group chat messages")
+void LLGroupChatListener::sendGroupIM(LLSD const &data)
{
- add("startIM",
- "Enter a group chat in group with UUID [\"id\"]\n"
- "Assumes the logged-in agent is already a member of this group.",
- &startIm_wrapper);
- add("endIM",
- "Leave a group chat in group with UUID [\"id\"]\n"
- "Assumes a prior successful startIM request.",
- &LLGroupActions::endIM,
- llsd::array("id"));
- add("sendIM",
- "send a groupchat IM",
- &send_message_wrapper,
- llsd::array("text", "session_id", "group_id"));
+ Response response(LLSD(), data);
+ if (!is_in_group(response, data))
+ {
+ return;
+ }
+
+ mIMThrottle(data["group_id"], data["message"]);
+}
+
+void LLGroupChatListener::sendGroupIM_(const LLUUID& group_id, const std::string& message)
+{
+ LLIMModel::sendMessage(LUA_PREFIX + message,
+ gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id),
+ group_id,
+ IM_SESSION_SEND);
}
-/*
- static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id,
- const LLUUID& other_participant_id, EInstantMessage dialog);
-*/
+
diff --git a/indra/newview/groupchatlistener.h b/indra/newview/groupchatlistener.h
index 3819ac59b7..a75fecb254 100644
--- a/indra/newview/groupchatlistener.h
+++ b/indra/newview/groupchatlistener.h
@@ -4,9 +4,9 @@
* @date 2011-04-11
* @brief
*
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2011, Linden Research, Inc.
+ * Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,15 +26,24 @@
* $/LicenseInfo$
*/
-#if ! defined(LL_GROUPCHATLISTENER_H)
-#define LL_GROUPCHATLISTENER_H
+#if ! defined(LL_LLGROUPCHATLISTENER_H)
+#define LL_LLGROUPCHATLISTENER_H
#include "lleventapi.h"
+#include "throttle.h"
-class GroupChatListener: public LLEventAPI
+class LLGroupChatListener: public LLEventAPI
{
public:
- GroupChatListener();
+ LLGroupChatListener();
+
+private:
+ void startGroupChat(LLSD const &data);
+ void leaveGroupChat(LLSD const &data);
+ void sendGroupIM(LLSD const &data);
+ void sendGroupIM_(const LLUUID& group_id, const std::string& message);
+
+ LogThrottle<LLError::LEVEL_DEBUG, void(const LLUUID&, const std::string&)> mIMThrottle;
};
-#endif /* ! defined(LL_GROUPCHATLISTENER_H) */
+#endif /* ! defined(LL_LLGROUPCHATLISTENER_H) */
diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh
index a027aaf6d1..3019e844d2 100755
--- a/indra/newview/linux_tools/wrapper.sh
+++ b/indra/newview/linux_tools/wrapper.sh
@@ -4,16 +4,9 @@
## These options are for self-assisted troubleshooting during this beta
## testing phase; you should not usually need to touch them.
-## - Avoids using any FMOD STUDIO audio driver.
-#export LL_BAD_FMODSTUDIO_DRIVER=x
## - Avoids using any OpenAL audio driver.
#export LL_BAD_OPENAL_DRIVER=x
-## - Avoids using the FMOD Studio or FMOD Ex PulseAudio audio driver.
-#export LL_BAD_FMOD_PULSEAUDIO=x
-## - Avoids using the FMOD Studio or FMOD Ex ALSA audio driver.
-#export LL_BAD_FMOD_ALSA=x
-
## - Avoids the optional OpenGL extensions which have proven most problematic
## on some hardware. Disabling this option may cause BETTER PERFORMANCE but
## may also cause CRASHES and hangs on some unstable combinations of drivers
@@ -34,16 +27,10 @@
## LL_GL_BLACKLIST which solves your problems.
#export LL_GL_BLACKLIST=abcdefghijklmno
-## - Some ATI/Radeon users report random X server crashes when the mouse
-## cursor changes shape. If you suspect that you are a victim of this
-## driver bug, try enabling this option and report whether it helps:
-#export LL_ATI_MOUSE_CURSOR_BUG=x
-
if [ "`uname -m`" = "x86_64" ]; then
echo '64-bit Linux detected.'
fi
-
## Everything below this line is just for advanced troubleshooters.
##-------------------------------------------------------------------
@@ -55,9 +42,6 @@ fi
#export LL_WRAPPER='gdb --args'
#export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp --suppressions=secondlife-i686.supp'
-## - Avoids an often-buggy X feature that doesn't really benefit us anyway.
-export SDL_VIDEO_X11_DGAMOUSE=0
-
## - The 'scim' GTK IM module widely crashes the viewer. Avoid it.
if [ "$GTK_IM_MODULE" = "scim" ]; then
export GTK_IM_MODULE=xim
@@ -67,13 +51,6 @@ if [ "$XMODIFIERS" = "" ]; then
export XMODIFIERS="@im=fcitx"
fi
-## - Automatically work around the ATI mouse cursor crash bug:
-## (this workaround is disabled as most fglrx users do not see the bug)
-#if lsmod | grep fglrx &>/dev/null ; then
-# export LL_ATI_MOUSE_CURSOR_BUG=x
-#fi
-
-
## Nothing worth editing below this line.
##-------------------------------------------------------------------
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 26c080bf89..6d03fdd61f 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -120,8 +120,8 @@ const F32 MIN_FIDGET_TIME = 8.f; // seconds
const F32 MAX_FIDGET_TIME = 20.f; // seconds
const S32 UI_FEATURE_VERSION = 1;
-// For version 1: 1 - inventory, 2 - gltf
-const S32 UI_FEATURE_FLAGS = 3;
+// For version 1, flag holds: 1 - inventory thumbnails, 2 - gltf, 4 - inventory favorites
+const S32 UI_FEATURE_FLAGS = 7;
// The agent instance.
LLAgent gAgent;
@@ -222,7 +222,6 @@ private:
LLVector3d mPosGlobal;
};
-
class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation
{
public:
@@ -603,7 +602,7 @@ void LLAgent::getFeatureVersionAndFlags(S32& version, S32& flags)
if (feature_version.isInteger())
{
version = feature_version.asInteger();
- flags = 1; // inventory flag
+ flags = 3; // show 'favorites' notification
}
else if (feature_version.isMap())
{
@@ -629,13 +628,8 @@ void LLAgent::showLatestFeatureNotification(const std::string key)
if (key == "inventory")
{
- // Notify user about new thumbnail support
- flag = 1;
- }
-
- if (key == "gltf")
- {
- flag = 2;
+ // Notify user about new favorites support
+ flag = 4;
}
if ((flags & flag) == 0)
@@ -842,7 +836,6 @@ void LLAgent::movePitch(F32 mag)
}
}
-
// Does this parcel allow you to fly?
bool LLAgent::canFly()
{
@@ -922,7 +915,6 @@ void LLAgent::setFlying(bool fly, bool fail_sound)
LLFloaterMove::setFlyingMode(fly);
}
-
// UI based mechanism of setting fly state
//-----------------------------------------------------------------------------
// toggleFlying()
@@ -1001,7 +993,6 @@ void LLAgent::capabilityReceivedCallback(const LLUUID &region_id, LLViewerRegion
}
}
-
//-----------------------------------------------------------------------------
// setRegion()
//-----------------------------------------------------------------------------
@@ -1107,7 +1098,6 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
mRegionChangedSignal();
}
-
//-----------------------------------------------------------------------------
// getRegion()
//-----------------------------------------------------------------------------
@@ -1116,7 +1106,6 @@ LLViewerRegion *LLAgent::getRegion() const
return mRegionp;
}
-
LLHost LLAgent::getRegionHost() const
{
if (mRegionp)
@@ -1147,7 +1136,6 @@ bool LLAgent::inPrelude()
return mRegionp && mRegionp->isPrelude();
}
-
std::string LLAgent::getRegionCapability(const std::string &name)
{
if (!mRegionp)
@@ -1156,7 +1144,6 @@ std::string LLAgent::getRegionCapability(const std::string &name)
return mRegionp->getCapability(name);
}
-
//-----------------------------------------------------------------------------
// canManageEstate()
//-----------------------------------------------------------------------------
@@ -1184,7 +1171,6 @@ void LLAgent::sendMessage()
gMessageSystem->sendMessage(mRegionp->getHost());
}
-
//-----------------------------------------------------------------------------
// sendReliableMessage()
//-----------------------------------------------------------------------------
@@ -1218,7 +1204,6 @@ LLVector3 LLAgent::getVelocity() const
}
}
-
//-----------------------------------------------------------------------------
// setPositionAgent()
//-----------------------------------------------------------------------------
@@ -1287,12 +1272,11 @@ const LLVector3 &LLAgent::getPositionAgent()
mFrameAgent.setOrigin(gAgentAvatarp->getPositionAgent());
}
else
- {
- mFrameAgent.setOrigin(gAgentAvatarp->getRenderPosition());
- }
+ {
+ mFrameAgent.setOrigin(gAgentAvatarp->getRenderPosition());
+ }
}
-
return mFrameAgent.getOrigin();
}
@@ -1301,7 +1285,6 @@ boost::signals2::connection LLAgent::whenPositionChanged(position_signal_t::slot
return mOnPositionChanged.connect(fn);
}
-
//-----------------------------------------------------------------------------
// getRegionsVisited()
//-----------------------------------------------------------------------------
@@ -1318,7 +1301,6 @@ F64 LLAgent::getDistanceTraveled() const
return mDistanceTraveled;
}
-
//-----------------------------------------------------------------------------
// getPosAgentFromGlobal()
//-----------------------------------------------------------------------------
@@ -1329,7 +1311,6 @@ LLVector3 LLAgent::getPosAgentFromGlobal(const LLVector3d &pos_global) const
return pos_agent;
}
-
//-----------------------------------------------------------------------------
// getPosGlobalFromAgent()
//-----------------------------------------------------------------------------
@@ -1345,7 +1326,6 @@ void LLAgent::sitDown()
setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
}
-
//-----------------------------------------------------------------------------
// resetAxes()
//-----------------------------------------------------------------------------
@@ -1354,7 +1334,6 @@ void LLAgent::resetAxes()
mFrameAgent.resetAxes();
}
-
// Copied from LLCamera::setOriginAndLookAt
// Look_at must be unit vector
//-----------------------------------------------------------------------------
@@ -1383,7 +1362,6 @@ void LLAgent::resetAxes(const LLVector3 &look_at)
mFrameAgent.setAxes(look_at, left, up);
}
-
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@@ -1392,7 +1370,6 @@ void LLAgent::rotate(F32 angle, const LLVector3 &axis)
mFrameAgent.rotate(angle, axis);
}
-
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@@ -1401,7 +1378,6 @@ void LLAgent::rotate(F32 angle, F32 x, F32 y, F32 z)
mFrameAgent.rotate(angle, x, y, z);
}
-
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@@ -1410,7 +1386,6 @@ void LLAgent::rotate(const LLMatrix3 &matrix)
mFrameAgent.rotate(matrix);
}
-
//-----------------------------------------------------------------------------
// rotate()
//-----------------------------------------------------------------------------
@@ -1419,7 +1394,6 @@ void LLAgent::rotate(const LLQuaternion &quaternion)
mFrameAgent.rotate(quaternion);
}
-
//-----------------------------------------------------------------------------
// getReferenceUpVector()
//-----------------------------------------------------------------------------
@@ -1448,51 +1422,71 @@ LLVector3 LLAgent::getReferenceUpVector()
return up_vector;
}
-
-// Radians, positive is forward into ground
+// Radians, positive is downward toward ground
//-----------------------------------------------------------------------------
// pitch()
//-----------------------------------------------------------------------------
void LLAgent::pitch(F32 angle)
{
- // don't let user pitch if pointed almost all the way down or up
+ if (gAgentCamera.getCameraMode() == CAMERA_MODE_THIRD_PERSON ||
+ gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+ {
+ // Backup the current orientation
+ LLCoordFrame saved_frame_agent(mFrameAgent);
- // A dot B = mag(A) * mag(B) * cos(angle between A and B)
- // so... cos(angle between A and B) = A dot B / mag(A) / mag(B)
- // = A dot B for unit vectors
+ // Optimistic rotation up/down (vertical angle can reach and exceed 0 or 180)
+ mFrameAgent.pitch(angle);
- LLVector3 skyward = getReferenceUpVector();
+ // Cosine of the angle between current agent At and Up directions
+ F32 agent_at_to_up_now_cos = saved_frame_agent.mXAxis * gAgentCamera.getCameraUpVector();
+ bool pitch_away_from_horizont = (angle < 0) ^ (agent_at_to_up_now_cos < 0);
+ // We always allow to pitch in direction to horizont (from zenith or from nadir)
+ if (!pitch_away_from_horizont)
+ return;
- // clamp pitch to limits
- if (angle >= 0.f)
- {
- const F32 look_down_limit = 179.f * DEG_TO_RAD;
- F32 angle_from_skyward = acos(mFrameAgent.getAtAxis() * skyward);
- if (angle_from_skyward + angle > look_down_limit)
+ // Current angle between agent At and Up directions
+ F32 agent_at_to_up_now = acos(agent_at_to_up_now_cos);
+ // Requested angle between agent At and Up directions
+ F32 agent_at_to_up_new = agent_at_to_up_now + angle;
+ F32 agent_at_to_up_new_sin = sin(agent_at_to_up_new);
+ // Overpitched? Then rollback
+ if (agent_at_to_up_new_sin < 1e-4)
{
- angle = look_down_limit - angle_from_skyward;
+ mFrameAgent = saved_frame_agent;
+ return;
}
- }
- else if (angle < 0.f)
- {
- const F32 look_up_limit = 5.f * DEG_TO_RAD;
- const LLVector3& viewer_camera_pos = LLViewerCamera::getInstance()->getOrigin();
- LLVector3 agent_focus_pos = getPosAgentFromGlobal(gAgentCamera.calcFocusPositionTargetGlobal());
- LLVector3 look_dir = agent_focus_pos - viewer_camera_pos;
- F32 angle_from_skyward = angle_between(look_dir, skyward);
- if (angle_from_skyward + angle < look_up_limit)
+
+ if (gAgentCamera.getCameraMode() == CAMERA_MODE_THIRD_PERSON ||
+ (isAgentAvatarValid() && gAgentAvatarp->getParent()))
{
- angle = look_up_limit - angle_from_skyward;
+ // Camera sight relative to agent frame (focus - offset)
+ LLVector3 camera_offset(gAgentCamera.getCameraOffsetInitial());
+ LLVector3 camera_focus(gAgentCamera.getFocusOffsetInitial());
+ LLVector3 camera_sight(camera_focus - camera_offset);
+ // 2D projection of the camera sight to the XZ plane
+ LLVector2 camera_sight_2d_vert(1, camera_sight[VZ]);
+ camera_sight_2d_vert.normalize();
+ // Cosine of the 2D angle between initial camera At and X axis (in the XZ plane)
+ F32 camera_sight_to_at_2d_vert_cos = camera_sight_2d_vert * LLVector2(LLVector3::x_axis);
+ F32 camera_sight_to_at_2d_vert = acos(camera_sight_to_at_2d_vert_cos);
+ // Requested angle between camera At and Up directions
+ F32 camera_at_to_up_new = agent_at_to_up_new - camera_sight_to_at_2d_vert;
+ F32 camera_at_to_up_new_sin = sin(camera_at_to_up_new);
+ // Overpitched? Then rollback
+ if (camera_at_to_up_new_sin < 1e-4)
+ {
+ mFrameAgent = saved_frame_agent;
+ return;
+ }
}
}
-
- if (fabs(angle) > 1e-4)
+ else
{
+ // No limitations in other modes
mFrameAgent.pitch(angle);
}
}
-
//-----------------------------------------------------------------------------
// roll()
//-----------------------------------------------------------------------------
@@ -1501,7 +1495,6 @@ void LLAgent::roll(F32 angle)
mFrameAgent.roll(angle);
}
-
//-----------------------------------------------------------------------------
// yaw()
//-----------------------------------------------------------------------------
@@ -1513,7 +1506,6 @@ void LLAgent::yaw(F32 angle)
}
}
-
// Returns a quat that represents the rotation of the agent in the absolute frame
//-----------------------------------------------------------------------------
// getQuat()
@@ -1539,7 +1531,6 @@ void LLAgent::setControlFlags(U32 mask)
mControlFlags |= mask;
}
-
//-----------------------------------------------------------------------------
// clearControlFlags()
//-----------------------------------------------------------------------------
@@ -1627,7 +1618,6 @@ bool LLAgent::isDoNotDisturb() const
return mIsDoNotDisturb;
}
-
//-----------------------------------------------------------------------------
// startAutoPilotGlobal()
//-----------------------------------------------------------------------------
@@ -1733,7 +1723,6 @@ void LLAgent::startAutoPilotGlobal(
mAutoPilotNoProgressFrameCount = 0;
}
-
//-----------------------------------------------------------------------------
// setAutoPilotTargetGlobal
//-----------------------------------------------------------------------------
@@ -1787,7 +1776,6 @@ void LLAgent::startFollowPilot(const LLUUID &leader_id, bool allow_flying, F32 s
allow_flying);
}
-
//-----------------------------------------------------------------------------
// stopAutoPilot()
//-----------------------------------------------------------------------------
@@ -1829,7 +1817,6 @@ void LLAgent::stopAutoPilot(bool user_cancel)
}
}
-
// Returns necessary agent pitch and yaw changes, radians.
//-----------------------------------------------------------------------------
// autoPilot()
@@ -2018,7 +2005,6 @@ void LLAgent::autoPilot(F32 *delta_yaw)
}
}
-
//-----------------------------------------------------------------------------
// propagate()
//-----------------------------------------------------------------------------
@@ -2039,18 +2025,19 @@ void LLAgent::propagate(const F32 dt)
}
// handle rotation based on keyboard levels
- constexpr F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
- F32 angle = YAW_RATE * gAgentCamera.getYawKey() * dt;
- if (fabs(angle) > 0.0f)
+ if (fabs(dt) > 1e-6)
{
- yaw(angle);
- }
+ if (fabs(gAgentCamera.getYawKey()) > 1e-6)
+ {
+ static const F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
+ yaw(YAW_RATE * gAgentCamera.getYawKey() * dt);
+ }
- constexpr F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
- angle = PITCH_RATE * gAgentCamera.getPitchKey() * dt;
- if (fabs(angle) > 0.0f)
- {
- pitch(angle);
+ if (fabs(gAgentCamera.getPitchKey()) > 1e-6)
+ {
+ static const F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
+ pitch(PITCH_RATE * gAgentCamera.getPitchKey() * dt);
+ }
}
// handle auto-land behavior
@@ -2212,7 +2199,6 @@ void LLAgent::clearRenderState(U8 clearstate)
mRenderState &= ~clearstate;
}
-
//-----------------------------------------------------------------------------
// getRenderState()
//-----------------------------------------------------------------------------
@@ -2254,6 +2240,7 @@ void LLAgent::endAnimationUpdateUI()
{
return;
}
+
if (gAgentCamera.getCameraMode() == gAgentCamera.getLastCameraMode())
{
// We're already done endAnimationUpdateUI for this transition.
@@ -2319,9 +2306,8 @@ void LLAgent::endAnimationUpdateUI()
mViewsPushed = false;
}
-
gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
- if( gMorphView )
+ if (gMorphView)
{
gMorphView->setVisible( false );
}
@@ -2329,7 +2315,7 @@ void LLAgent::endAnimationUpdateUI()
// Disable mouselook-specific animations
if (isAgentAvatarValid())
{
- if( gAgentAvatarp->isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
+ if (gAgentAvatarp->isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS))
{
if (gAgentAvatarp->mSignaledAnimations.find(ANIM_AGENT_AIM_RIFLE_R) != gAgentAvatarp->mSignaledAnimations.end())
{
@@ -2948,7 +2934,6 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)
}
}
-
void LLAgent::processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity)
{
U8 maturity = SIM_ACCESS_MIN;
@@ -3018,7 +3003,6 @@ void LLAgent::changeInterestListMode(const std::string &new_mode)
}
}
-
bool LLAgent::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure)
{
if (getRegion())
@@ -3345,7 +3329,6 @@ void LLAgent::sendAnimationStateReset()
sendReliableMessage();
}
-
// Send a message to the region to revoke sepecified permissions on ALL scripts in the region
// If the target is an object in the region, permissions in scripts on that object are cleared.
// If it is the region ID, all scripts clear the permissions for this agent
@@ -4275,7 +4258,6 @@ void LLAgent::onCapabilitiesReceivedAfterTeleport()
check_merchant_status();
}
-
void LLAgent::teleportRequest(
const U64& region_handle,
const LLVector3& pos_local,
@@ -4375,7 +4357,6 @@ void LLAgent::doTeleportViaLure(const LLUUID& lure_id, bool godlike)
}
}
-
// James Cook, July 28, 2005
void LLAgent::teleportCancel()
{
@@ -4500,7 +4481,6 @@ LLAgent::ETeleportState LLAgent::getTeleportState() const
TELEPORT_NONE : mTeleportState;
}
-
void LLAgent::setTeleportState(ETeleportState state)
{
if (mTeleportRequest && (state != TELEPORT_NONE) && (mTeleportRequest->getStatus() == LLTeleportRequest::kFailed))
@@ -4545,7 +4525,6 @@ void LLAgent::setTeleportState(ETeleportState state)
}
}
-
void LLAgent::stopCurrentAnimations()
{
LL_DEBUGS("Avatar") << "Stopping current animations" << LL_ENDL;
@@ -4660,7 +4639,6 @@ void LLAgent::stopFidget()
gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP);
}
-
void LLAgent::requestEnterGodMode()
{
LLMessageSystem* msg = gMessageSystem;
@@ -4781,7 +4759,6 @@ void LLAgent::sendAgentUpdateUserInfo(const std::string& directory_visibility)
}
}
-
void LLAgent::updateAgentUserInfoCoro(std::string capurl, std::string directory_visibility)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
@@ -4972,6 +4949,218 @@ void LLAgent::renderAutoPilotTarget()
}
}
+static U64 g_lastUpdateTime { 0 };
+static F32 g_deltaTime { 0.0f };
+static S32 g_lastUpdateFrame { 0 };
+static S32 g_deltaFrame { 0 };
+
+void LLAgent::applyExternalActionFlags(U32 outer_flags)
+{
+ llassert(LLCoros::on_main_thread_main_coro());
+ assert(LLGameControl::isEnabled() && LLGameControl::willControlAvatar());
+ mExternalActionFlags = outer_flags;
+
+ // HACK: AGENT_CONTROL_NUDGE_AT_NEG is used to toggle Flycam
+ if ((mExternalActionFlags & AGENT_CONTROL_NUDGE_AT_NEG) > 0)
+ {
+ if (mToggleFlycam)
+ {
+ mUsingFlycam = !mUsingFlycam;
+ if (mUsingFlycam)
+ {
+ // copy main camera transform to flycam
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ mFlycam.setTransform(camera->getOrigin(), camera->getQuaternion());
+ mFlycam.setView(camera->getView());
+ mLastFlycamUpdate = LLFrameTimer::getTotalTime();
+ }
+ }
+ mToggleFlycam = false;
+ }
+ else
+ {
+ mToggleFlycam = true;
+ }
+
+ // measure delta time and frame
+ // Note: it is possible for the deltas to be very large
+ // and it is the duty of the code that uses them to clamp as necessary
+ U64 now = LLFrameTimer::getTotalTime();
+ g_deltaTime = F32(now - g_lastUpdateTime) / (F32)(USEC_PER_SEC);
+ g_lastUpdateTime = now;
+
+ S32 frame_count = LLFrameTimer::getFrameCount();
+ g_deltaFrame = frame_count - g_lastUpdateFrame;
+ g_lastUpdateFrame = frame_count;
+
+ if (mUsingFlycam)
+ {
+ // Flycam will be updated later by exernal context
+ return;
+ }
+
+ S32 direction = (S32)(mExternalActionFlags & AGENT_CONTROL_AT_POS)
+ - (S32)((mExternalActionFlags & AGENT_CONTROL_AT_NEG) >> 1);
+ if (direction != 0)
+ {
+ moveAt(direction);
+ }
+
+ static U32 last_non_fly_frame = 0;
+ static U64 last_non_fly_time = 0;
+ direction = (S32)(mExternalActionFlags & AGENT_CONTROL_UP_POS)
+ - (S32)((mExternalActionFlags & AGENT_CONTROL_UP_NEG) >> 1);
+ if (direction != 0)
+ {
+ // HACK: this auto-fly logic based on original code still extant in llviewerinput.cpp::agent_jump()
+ // but has been cleaned up.
+ // TODO?: DRY this logic
+ if (direction > 0)
+ {
+ if (!getFlying()
+ && !upGrabbed()
+ && gSavedSettings.getBOOL("AutomaticFly"))
+ {
+ constexpr F32 FLY_TIME = 0.5f;
+ constexpr U32 FLY_FRAMES = 4;
+ F32 delta_time = (F32)(now - last_non_fly_time) / (F32)(USEC_PER_SEC);
+ U32 delta_frames = frame_count - last_non_fly_frame;
+ if( delta_time > FLY_TIME
+ && delta_frames > FLY_FRAMES)
+ {
+ setFlying(true);
+ }
+ }
+ }
+ else
+ {
+ last_non_fly_frame = frame_count;
+ last_non_fly_time = now;
+ }
+
+ moveUp(direction);
+ }
+ else if (!getFlying())
+ {
+ last_non_fly_frame = frame_count;
+ last_non_fly_time = now;
+ }
+
+ direction = (S32)(mExternalActionFlags & AGENT_CONTROL_LEFT_POS)
+ - (S32)((mExternalActionFlags & AGENT_CONTROL_LEFT_NEG) >> 1);
+ if (direction != 0)
+ {
+ moveLeft(direction);
+ }
+
+ direction = (S32)(mExternalActionFlags & AGENT_CONTROL_YAW_POS)
+ - (S32)((mExternalActionFlags & AGENT_CONTROL_YAW_NEG) >> 1);
+ if (direction != 0)
+ {
+ F32 sign = (direction < 0 ? -1.0f : 1.0f);
+ // HACK: hard-code 3.0 seconds for YawRate measure. It is simpler,
+ // and the missing variable yaw rate is unnoticeable.
+ moveYaw(sign * LLFloaterMove::getYawRate(3.0f));
+ }
+
+ {
+ F32 pitch = ((mExternalActionFlags & AGENT_CONTROL_PITCH_POS) > 0 ? 1.0f : 0.0f)
+ - ((mExternalActionFlags & AGENT_CONTROL_PITCH_NEG) > 0 ? 1.0f : 0.0f);
+ movePitch(pitch);
+ }
+
+ if ((mExternalActionFlags & AGENT_CONTROL_FLY) > 0)
+ {
+ if (mToggleFly)
+ {
+ setFlying(!getFlying());
+ }
+ mToggleFly = false;
+ }
+ else
+ {
+ mToggleFly = true;
+ }
+
+ if (mExternalActionFlags & AGENT_CONTROL_STOP)
+ {
+ setControlFlags(AGENT_CONTROL_STOP);
+ }
+
+ // HACK: AGENT_CONTROL_NUDGE_AT_POS is used to toggle running
+ if ((mExternalActionFlags & AGENT_CONTROL_NUDGE_AT_POS) > 0)
+ {
+ if (mToggleRun)
+ {
+ if (getRunning())
+ {
+ clearRunning();
+ sendWalkRun(false);
+ }
+ else
+ {
+ setRunning();
+ sendWalkRun(true);
+ }
+ }
+ mToggleRun = false;
+ }
+ else
+ {
+ mToggleRun = true;
+ }
+}
+
+void LLAgent::pressGameControlButton(U8 button_index)
+{
+ mGameControlButtonsFromKeys |= (1U << button_index);
+}
+
+void LLAgent::releaseGameControlButton(U8 button_index)
+{
+ mGameControlButtonsFromKeys &= !(1U << button_index);
+}
+
+void LLAgent::updateFlycam()
+{
+ // Note: flycam_inputs arrive in range [-1,1]
+ std::vector<F32> flycam_inputs;
+ LLGameControl::getFlycamInputs(flycam_inputs);
+
+ // Note: no matter how flycam_inputs are mapped to the controller
+ // they arrive in the following order:
+ constexpr S32 FLYCAM_ADVANCE = 0;
+ constexpr S32 FLYCAM_PAN = 1;
+ constexpr S32 FLYCAM_RISE = 2;
+ constexpr S32 FLYCAM_PITCH = 3;
+ constexpr S32 FLYCAM_YAW = 4;
+ constexpr S32 FLYCAM_ZOOM = 5;
+
+ LLVector3 linear_velocity(
+ flycam_inputs[FLYCAM_ADVANCE],
+ flycam_inputs[FLYCAM_PAN],
+ flycam_inputs[FLYCAM_RISE]);
+ constexpr F32 MAX_FLYCAM_SPEED = 10.0f;
+ mFlycam.setLinearVelocity(MAX_FLYCAM_SPEED * linear_velocity);
+
+ mFlycam.setPitchRate(flycam_inputs[FLYCAM_PITCH]);
+ mFlycam.setYawRate(flycam_inputs[FLYCAM_YAW]);
+ mFlycam.setZoomRate(flycam_inputs[FLYCAM_ZOOM]);
+
+ mFlycam.integrate(g_deltaTime);
+
+ LLVector3 pos;
+ LLQuaternion rot;
+ mFlycam.getTransform(pos, rot);
+ LLMatrix3 mat(rot);
+ LLViewerCamera::getInstance()->setOrigin(pos);
+ LLViewerCamera::getInstance()->mXAxis = LLVector3(mat.mMatrix[0]);
+ LLViewerCamera::getInstance()->mYAxis = LLVector3(mat.mMatrix[1]);
+ LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]);
+
+ LLViewerCamera::getInstance()->setView(mFlycam.getView());
+}
+
/********************************************************************************/
//-----------------------------------------------------------------------------
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index c1d3c6c14b..489131d974 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -33,6 +33,8 @@
#include "llcharacter.h"
#include "llcoordframe.h" // for mFrameAgent
#include "llavatarappearancedefines.h"
+#include "llflycam.h"
+#include "llkeyboard.h"
#include "llpermissionsflags.h"
#include "llevents.h"
#include "v3dmath.h"
@@ -478,6 +480,7 @@ public:
void resetControlFlags();
bool anyControlGrabbed() const; // True iff a script has taken over a control
bool isControlGrabbed(S32 control_index) const;
+ bool isUsingFlycam() const { return mUsingFlycam; }
// Send message to simulator to force grabbed controls to be
// released, in case of a poorly written script.
void forceReleaseControls();
@@ -485,7 +488,39 @@ public:
private:
S32 mControlsTakenCount[TOTAL_CONTROLS];
S32 mControlsTakenPassedOnCount[TOTAL_CONTROLS];
- U32 mControlFlags; // Replacement for the mFooKey's
+ // mControlFlags is a bitmask of behavior instructions for compact
+ // transmission to the server. It does NOT represent "input", rather
+ // the consequences of it, which will sometimes depend on "state".
+ U32 mControlFlags;
+
+ //--------------------------------------------------------------------
+ // GameControls
+ //--------------------------------------------------------------------
+public:
+ // ActionFlags are similar to, but not the same as, ControlFlags!
+ // An 'ActionFlags' bitmask stores 'simplified input' from key/button
+ // presses that correspond to avatar/camera movement actions
+ // whereas 'mControlFlags' are a more complicated set of behavior bits
+ // computed as a function of input and state, and are sent to the server
+ // to steer its character controller for the avatar.
+ //
+ void applyExternalActionFlags(U32 flags);
+ void updateFlycam();
+
+ void pressGameControlButton(U8 button);
+ void releaseGameControlButton(U8 button);
+ U32 getGameControlButtonsFromKeys() const { return mGameControlButtonsFromKeys; }
+
+private:
+
+ U64 mLastFlycamUpdate { 0 };
+ U32 mExternalActionFlags { 0 };
+ U32 mGameControlButtonsFromKeys { 0 };
+ LLFlycam mFlycam;
+ bool mToggleFly { true };
+ bool mToggleRun { true };
+ bool mToggleFlycam { true };
+ bool mUsingFlycam { false };
//--------------------------------------------------------------------
// Animations
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 40cb6f6265..418d3d150b 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -1231,7 +1231,7 @@ void LLAgentCamera::updateCamera()
}
//NOTE - this needs to be integrated into a general upVector system here within llAgent.
- if ( camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
+ if (camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar)
{
mCameraUpVector = mFollowCam.getUpVector();
}
@@ -1462,13 +1462,12 @@ void LLAgentCamera::updateCamera()
// LL_INFOS() << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << LL_ENDL;
LLVector3 focus_agent = gAgent.getPosAgentFromGlobal(mFocusGlobal);
+ LLVector3 position_agent = gAgent.getPosAgentFromGlobal(camera_pos_global);
- mCameraPositionAgent = gAgent.getPosAgentFromGlobal(camera_pos_global);
+ // Try to move the camera
- // Move the camera
-
- LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
- //LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
+ if (!LLViewerCamera::getInstance()->updateCameraLocation(position_agent, mCameraUpVector, focus_agent))
+ return;
// Change FOV
LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / (1.f + mCameraCurrentFOVZoomFactor));
@@ -1476,7 +1475,7 @@ void LLAgentCamera::updateCamera()
// follow camera when in customize mode
if (cameraCustomizeAvatar())
{
- setLookAt(LOOKAT_TARGET_FOCUS, NULL, mCameraPositionAgent);
+ setLookAt(LOOKAT_TARGET_FOCUS, NULL, position_agent);
}
// update the travel distance stat
@@ -1495,8 +1494,8 @@ void LLAgentCamera::updateCamera()
LLVector3 head_pos = gAgentAvatarp->mHeadp->getWorldPosition() +
LLVector3(0.08f, 0.f, 0.05f) * gAgentAvatarp->mHeadp->getWorldRotation() +
LLVector3(0.1f, 0.f, 0.f) * gAgentAvatarp->mPelvisp->getWorldRotation();
- LLVector3 diff = mCameraPositionAgent - head_pos;
- diff = diff * ~gAgentAvatarp->mRoot->getWorldRotation();
+ LLVector3 diff = position_agent - head_pos;
+ diff *= ~gAgentAvatarp->mRoot->getWorldRotation();
LLJoint* torso_joint = gAgentAvatarp->mTorsop;
LLJoint* chest_joint = gAgentAvatarp->mChestp;
@@ -1988,16 +1987,6 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(bool *hit_limit)
isConstrained = true;
}
}
-
-// JC - Could constrain camera based on parcel stuff here.
-// LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(camera_position_global);
-//
-// if (regionp && !regionp->mParcelOverlay->isBuildCameraAllowed(regionp->getPosRegionFromGlobal(camera_position_global)))
-// {
-// camera_position_global = last_position_global;
-//
-// isConstrained = true;
-// }
}
// Don't let camera go underground
@@ -2266,7 +2255,8 @@ void LLAgentCamera::changeCameraToFollow(bool animate)
mCameraMode = CAMERA_MODE_FOLLOW;
// bang-in the current focus, position, and up vector of the follow cam
- mFollowCam.reset(mCameraPositionAgent, LLViewerCamera::getInstance()->getPointOfInterest(), LLVector3::z_axis);
+ const LLViewerCamera& camera = LLViewerCamera::instance();
+ mFollowCam.reset(camera.getOrigin(), camera.getPointOfInterest(), LLVector3::z_axis);
if (gBasicToolset)
{
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index 52571f3c55..d277fd6158 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -112,6 +112,7 @@ private:
//--------------------------------------------------------------------
public:
void switchCameraPreset(ECameraPreset preset);
+ ECameraPreset getCameraPreset() const { return mCameraPreset; }
/** Determines default camera offset depending on the current camera preset */
LLVector3 getCameraOffsetInitial();
/** Determines default focus offset depending on the current camera preset */
@@ -138,13 +139,14 @@ private:
//--------------------------------------------------------------------
public:
LLVector3d getCameraPositionGlobal() const;
- const LLVector3 &getCameraPositionAgent() const;
+ const LLVector3& getCameraPositionAgent() const;
LLVector3d calcCameraPositionTargetGlobal(bool *hit_limit = NULL); // Calculate the camera position target
F32 getCameraMinOffGround(); // Minimum height off ground for this mode, meters
void setCameraCollidePlane(const LLVector4 &plane) { mCameraCollidePlane = plane; }
bool calcCameraMinDistance(F32 &obj_min_distance);
- F32 getCurrentCameraBuildOffset() { return (F32)mCameraFocusOffset.length(); }
+ F32 getCurrentCameraBuildOffset() const { return (F32)mCameraFocusOffset.length(); }
void clearCameraLag() { mCameraLag.clearVec(); }
+ const LLVector3& getCameraUpVector() const { return mCameraUpVector; }
private:
LLVector3 getAvatarRootPosition();
@@ -154,7 +156,6 @@ private:
F32 mCameraCurrentFOVZoomFactor; // Interpolated fov zoom
LLVector4 mCameraCollidePlane; // Colliding plane for camera
F32 mCameraZoomFraction; // Mousewheel driven fraction of zoom
- LLVector3 mCameraPositionAgent; // Camera position in agent coordinates
LLVector3 mCameraVirtualPositionAgent; // Camera virtual position (target) before performing FOV zoom
LLVector3d mCameraSmoothingLastPositionGlobal;
LLVector3d mCameraSmoothingLastPositionAgent;
@@ -278,7 +279,7 @@ public:
F32 getAgentHUDTargetZoom();
void resetCameraZoomFraction();
- F32 getCurrentCameraZoomFraction() { return mCameraZoomFraction; }
+ F32 getCurrentCameraZoomFraction() const { return mCameraZoomFraction; }
//--------------------------------------------------------------------
// Pan
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index 0c120ae01d..2810cd6706 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -31,23 +31,34 @@
#include "llagentlistener.h"
#include "llagent.h"
+#include "llagentcamera.h"
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
#include "llvoavatar.h"
#include "llcommandhandler.h"
+#include "llinventorymodel.h"
#include "llslurl.h"
#include "llurldispatcher.h"
+#include "llviewercontrol.h"
#include "llviewernetwork.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
+#include "llvoavatarself.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "lltoolgrab.h"
#include "llhudeffectlookat.h"
-#include "llagentcamera.h"
+#include "llviewercamera.h"
+#include "resultset.h"
+#include <functional>
+
+static const F64 PLAY_ANIM_THROTTLE_PERIOD = 1.f;
LLAgentListener::LLAgentListener(LLAgent &agent)
: LLEventAPI("LLAgent",
"LLAgent listener to (e.g.) teleport, sit, stand, etc."),
+ mPlayAnimThrottle("playAnimation", &LLAgentListener::playAnimation_, this, PLAY_ANIM_THROTTLE_PERIOD),
mAgent(agent)
{
add("requestTeleport",
@@ -69,13 +80,6 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
add("resetAxes",
"Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])",
&LLAgentListener::resetAxes);
- add("getAxes",
- "Obsolete - use getPosition instead\n"
- "Send information about the agent's orientation on [\"reply\"]:\n"
- "[\"euler\"]: map of {roll, pitch, yaw}\n"
- "[\"quat\"]: array of [x, y, z, w] quaternion values",
- &LLAgentListener::getAxes,
- LLSDMap("reply", LLSD()));
add("getPosition",
"Send information about the agent's position and orientation on [\"reply\"]:\n"
"[\"region\"]: array of region {x, y, z} position\n"
@@ -87,33 +91,34 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
add("startAutoPilot",
"Start the autopilot system using the following parameters:\n"
"[\"target_global\"]: array of target global {x, y, z} position\n"
- "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n"
+ "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]\n"
"[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n"
"[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n"
- "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]"
- "[\"allow_flying\"]: allow flying during autopilot [default: True]",
- //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n"
- //"[\"callback_data\"]: data to send back during a callback [default: none]",
- &LLAgentListener::startAutoPilot);
+ "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]\n"
+ "[\"allow_flying\"]: allow flying during autopilot [default: True]\n"
+ "event with [\"success\"] flag is sent to 'LLAutopilot' event pump, when auto pilot is terminated",
+ &LLAgentListener::startAutoPilot,
+ llsd::map("target_global", LLSD()));
add("getAutoPilot",
"Send information about current state of the autopilot system to [\"reply\"]:\n"
"[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n"
"[\"target_global\"]: array of target global {x, y, z} position\n"
"[\"leader_id\"]: uuid of target autopilot is following\n"
- "[\"stop_distance\"]: target maximum distance from target\n"
+ "[\"stop_distance\"]: maximum stop distance from target\n"
"[\"target_distance\"]: last known distance from target\n"
"[\"use_rotation\"]: boolean indicating if autopilot has a target facing rotation\n"
"[\"target_facing\"]: array of {x, y} target direction to face\n"
"[\"rotation_threshold\"]: target maximum angle from target facing rotation\n"
"[\"behavior_name\"]: name of the autopilot behavior",
&LLAgentListener::getAutoPilot,
- LLSDMap("reply", LLSD()));
+ llsd::map("reply", LLSD()));
add("startFollowPilot",
"[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n"
"[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n"
"[\"allow_flying\"]: allow flying during autopilot [default: True]\n"
- "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]",
- &LLAgentListener::startFollowPilot);
+ "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]",
+ &LLAgentListener::startFollowPilot,
+ llsd::map("reply", LLSD()));
add("setAutoPilotTarget",
"Update target for currently running autopilot:\n"
"[\"target_global\"]: array of target global {x, y, z} position",
@@ -138,6 +143,69 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
"[\"contrib\"]: user's land contribution to this group\n",
&LLAgentListener::getGroups,
LLSDMap("reply", LLSD()));
+ //camera params are similar to LSL, see https://wiki.secondlife.com/wiki/LlSetCameraParams
+ add("setCameraParams",
+ "Set Follow camera params, and then activate it:\n"
+ "[\"camera_pos\"]: vector3, camera position in region coordinates\n"
+ "[\"focus_pos\"]: vector3, what the camera is aimed at (in region coordinates)\n"
+ "[\"focus_offset\"]: vector3, adjusts the camera focus position relative to the target, default is (1, 0, 0)\n"
+ "[\"distance\"]: float (meters), distance the camera wants to be from its target, default is 3\n"
+ "[\"focus_threshold\"]: float (meters), sets the radius of a sphere around the camera's target position within which its focus is not affected by target motion, default is 1\n"
+ "[\"camera_threshold\"]: float (meters), sets the radius of a sphere around the camera's ideal position within which it is not affected by target motion, default is 1\n"
+ "[\"focus_lag\"]: float (seconds), how much the camera lags as it tries to aim towards the target, default is 0.1\n"
+ "[\"camera_lag\"]: float (seconds), how much the camera lags as it tries to move towards its 'ideal' position, default is 0.1\n"
+ "[\"camera_pitch\"]: float (degrees), adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance, default is 0\n"
+ "[\"behindness_angle\"]: float (degrees), sets the angle in degrees within which the camera is not constrained by changes in target rotation, default is 10\n"
+ "[\"behindness_lag\"]: float (seconds), sets how strongly the camera is forced to stay behind the target if outside of behindness angle, default is 0\n"
+ "[\"camera_locked\"]: bool, locks the camera position so it will not move\n"
+ "[\"focus_locked\"]: bool, locks the camera focus so it will not move",
+ &LLAgentListener::setFollowCamParams);
+ add("setFollowCamActive",
+ "Turns on or off scripted control of the camera using boolean [\"active\"]",
+ &LLAgentListener::setFollowCamActive,
+ llsd::map("active", LLSD()));
+ add("removeCameraParams",
+ "Reset Follow camera params",
+ &LLAgentListener::removeFollowCamParams);
+
+ add("playAnimation",
+ "Play [\"item_id\"] animation locally (by default) or [\"inworld\"] (when set to true)",
+ &LLAgentListener::playAnimation,
+ llsd::map("item_id", LLSD(), "reply", LLSD()));
+ add("stopAnimation",
+ "Stop playing [\"item_id\"] animation",
+ &LLAgentListener::stopAnimation,
+ llsd::map("item_id", LLSD(), "reply", LLSD()));
+ add("getAnimationInfo",
+ "Return information about [\"item_id\"] animation",
+ &LLAgentListener::getAnimationInfo,
+ llsd::map("item_id", LLSD(), "reply", LLSD()));
+
+ add("getID",
+ "Return your own avatar ID",
+ &LLAgentListener::getID,
+ llsd::map("reply", LLSD()));
+
+ add("getNearbyAvatarsList",
+ "Return result set key [\"result\"] for nearby avatars in a range of [\"dist\"]\n"
+ "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n"
+ "reply contains \"result\" table with \"id\", \"name\", \"global_pos\", \"region_pos\", \"region_id\" fields",
+ &LLAgentListener::getNearbyAvatarsList,
+ llsd::map("reply", LLSD()));
+
+ add("getNearbyObjectsList",
+ "Return result set key [\"result\"] for nearby objects in a range of [\"dist\"]\n"
+ "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n"
+ "reply contains \"result\" table with \"id\", \"global_pos\", \"region_pos\", \"region_id\" fields",
+ &LLAgentListener::getNearbyObjectsList,
+ llsd::map("reply", LLSD()));
+
+ add("getAgentScreenPos",
+ "Return screen position of the [\"avatar_id\"] avatar or own avatar if not specified\n"
+ "reply contains \"x\", \"y\" coordinates and \"onscreen\" flag to indicate if it's actually in within the current window\n"
+ "avatar render position is used as the point",
+ &LLAgentListener::getAgentScreenPos,
+ llsd::map("reply", LLSD()));
}
void LLAgentListener::requestTeleport(LLSD const & event_data) const
@@ -168,7 +236,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
//mAgent.getAvatarObject()->sitOnObject();
// shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand()
// *TODO - find a permanent place to share this code properly.
-
+ Response response(LLSD(), event_data);
LLViewerObject *object = NULL;
if (event_data.has("obj_uuid"))
{
@@ -177,7 +245,13 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
else if (event_data.has("position"))
{
LLVector3 target_position = ll_vector3_from_sd(event_data["position"]);
- object = findObjectClosestTo(target_position);
+ object = findObjectClosestTo(target_position, true);
+ }
+ else
+ {
+ //just sit on the ground
+ mAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+ return;
}
if (object && object->getPCode() == LL_PCODE_VOLUME)
@@ -194,8 +268,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
}
else
{
- LL_WARNS() << "LLAgent requestSit could not find the sit target: "
- << event_data << LL_ENDL;
+ response.error("requestSit could not find the sit target");
}
}
@@ -205,7 +278,7 @@ void LLAgentListener::requestStand(LLSD const & event_data) const
}
-LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & position ) const
+LLViewerObject * LLAgentListener::findObjectClosestTo(const LLVector3 & position, bool sit_target) const
{
LLViewerObject *object = NULL;
@@ -216,8 +289,13 @@ LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & positio
while (cur_index < num_objects)
{
LLViewerObject * cur_object = gObjectList.getObject(cur_index++);
- if (cur_object)
- { // Calculate distance from the target position
+ if (cur_object && !cur_object->isAttachment())
+ {
+ if(sit_target && (cur_object->getPCode() != LL_PCODE_VOLUME))
+ {
+ continue;
+ }
+ // Calculate distance from the target position
LLVector3 target_diff = cur_object->getPositionRegion() - position;
F32 distance_to_target = target_diff.length();
if (distance_to_target < min_distance)
@@ -296,22 +374,6 @@ void LLAgentListener::resetAxes(const LLSD& event_data) const
}
}
-void LLAgentListener::getAxes(const LLSD& event_data) const
-{
- LLQuaternion quat(mAgent.getQuat());
- F32 roll, pitch, yaw;
- quat.getEulerAngles(&roll, &pitch, &yaw);
- // The official query API for LLQuaternion's [x, y, z, w] values is its
- // public member mQ...
- LLSD reply = LLSD::emptyMap();
- reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ));
- reply["euler"] = LLSD::emptyMap();
- reply["euler"]["roll"] = roll;
- reply["euler"]["pitch"] = pitch;
- reply["euler"]["yaw"] = yaw;
- sendReply(reply, event_data);
-}
-
void LLAgentListener::getPosition(const LLSD& event_data) const
{
F32 roll, pitch, yaw;
@@ -333,14 +395,13 @@ void LLAgentListener::getPosition(const LLSD& event_data) const
void LLAgentListener::startAutoPilot(LLSD const & event_data)
{
- LLQuaternion target_rotation_value;
LLQuaternion* target_rotation = NULL;
if (event_data.has("target_rotation"))
{
- target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]);
+ LLQuaternion target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]);
target_rotation = &target_rotation_value;
}
- // *TODO: Use callback_pump and callback_data
+
F32 rotation_threshold = 0.03f;
if (event_data.has("rotation_threshold"))
{
@@ -360,13 +421,24 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data)
stop_distance = (F32)event_data["stop_distance"].asReal();
}
+ std::string behavior_name = LLCoros::getName();
+ if (event_data.has("behavior_name"))
+ {
+ behavior_name = event_data["behavior_name"].asString();
+ }
+
// Clear follow target, this is doing a path
mFollowTarget.setNull();
+ auto finish_cb = [](bool success, void*)
+ {
+ LLEventPumps::instance().obtain("LLAutopilot").post(llsd::map("success", success));
+ };
+
mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]),
- event_data["behavior_name"],
+ behavior_name,
target_rotation,
- NULL, NULL,
+ finish_cb, NULL,
stop_distance,
rotation_threshold,
allow_flying);
@@ -374,7 +446,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data)
void LLAgentListener::getAutoPilot(const LLSD& event_data) const
{
- LLSD reply = LLSD::emptyMap();
+ Response reply(LLSD(), event_data);
LLSD::Boolean enabled = mAgent.getAutoPilot();
reply["enabled"] = enabled;
@@ -403,12 +475,11 @@ void LLAgentListener::getAutoPilot(const LLSD& event_data) const
reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold();
reply["behavior_name"] = mAgent.getAutoPilotBehaviorName();
reply["fly"] = (LLSD::Boolean) mAgent.getFlying();
-
- sendReply(reply, event_data);
}
void LLAgentListener::startFollowPilot(LLSD const & event_data)
{
+ Response response(LLSD(), event_data);
LLUUID target_id;
bool allow_flying = true;
@@ -442,6 +513,10 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data)
}
}
}
+ else
+ {
+ return response.error("'leader_id' or 'avatar_name' should be specified");
+ }
F32 stop_distance = 0.f;
if (event_data.has("stop_distance"))
@@ -449,13 +524,16 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data)
stop_distance = (F32)event_data["stop_distance"].asReal();
}
- if (target_id.notNull())
+ if (!gObjectList.findObject(target_id))
{
- mAgent.setFlying(allow_flying);
- mFollowTarget = target_id; // Save follow target so we can report distance later
-
- mAgent.startFollowPilot(target_id, allow_flying, stop_distance);
+ std::string target_info = event_data.has("leader_id") ? event_data["leader_id"] : event_data["avatar_name"];
+ return response.error(stringize("Target ", std::quoted(target_info), " was not found"));
}
+
+ mAgent.setFlying(allow_flying);
+ mFollowTarget = target_id; // Save follow target so we can report distance later
+
+ mAgent.startFollowPilot(target_id, allow_flying, stop_distance);
}
void LLAgentListener::setAutoPilotTarget(LLSD const & event_data) const
@@ -519,3 +597,252 @@ void LLAgentListener::getGroups(const LLSD& event) const
}
sendReply(LLSDMap("groups", reply), event);
}
+
+/*----------------------------- camera control -----------------------------*/
+// specialize LLSDParam to support (const LLVector3&) arguments -- this
+// wouldn't even be necessary except that the relevant LLVector3 constructor
+// is explicitly explicit
+template <>
+class LLSDParam<const LLVector3&>: public LLSDParamBase
+{
+public:
+ LLSDParam(const LLSD& value): value(LLVector3(value)) {}
+
+ operator const LLVector3&() const { return value; }
+
+private:
+ LLVector3 value;
+};
+
+// accept any of a number of similar LLFollowCamMgr methods with different
+// argument types, and return a wrapper lambda that accepts LLSD and converts
+// to the target argument type
+template <typename T>
+auto wrap(void (LLFollowCamMgr::*method)(const LLUUID& source, T arg))
+{
+ return [method](LLFollowCamMgr& followcam, const LLUUID& source, const LLSD& arg)
+ { (followcam.*method)(source, LLSDParam<T>(arg)); };
+}
+
+// table of supported LLFollowCamMgr methods,
+// with the corresponding setFollowCamParams() argument keys
+static std::pair<std::string, std::function<void(LLFollowCamMgr&, const LLUUID&, const LLSD&)>>
+cam_params[] =
+{
+ { "camera_pos", wrap(&LLFollowCamMgr::setPosition) },
+ { "focus_pos", wrap(&LLFollowCamMgr::setFocus) },
+ { "focus_offset", wrap(&LLFollowCamMgr::setFocusOffset) },
+ { "camera_locked", wrap(&LLFollowCamMgr::setPositionLocked) },
+ { "focus_locked", wrap(&LLFollowCamMgr::setFocusLocked) },
+ { "distance", wrap(&LLFollowCamMgr::setDistance) },
+ { "focus_threshold", wrap(&LLFollowCamMgr::setFocusThreshold) },
+ { "camera_threshold", wrap(&LLFollowCamMgr::setPositionThreshold) },
+ { "focus_lag", wrap(&LLFollowCamMgr::setFocusLag) },
+ { "camera_lag", wrap(&LLFollowCamMgr::setPositionLag) },
+ { "camera_pitch", wrap(&LLFollowCamMgr::setPitch) },
+ { "behindness_lag", wrap(&LLFollowCamMgr::setBehindnessLag) },
+ { "behindness_angle", wrap(&LLFollowCamMgr::setBehindnessAngle) },
+};
+
+void LLAgentListener::setFollowCamParams(const LLSD& event) const
+{
+ auto& followcam{ LLFollowCamMgr::instance() };
+ for (const auto& pair : cam_params)
+ {
+ if (event.has(pair.first))
+ {
+ pair.second(followcam, gAgentID, event[pair.first]);
+ }
+ }
+ followcam.setCameraActive(gAgentID, true);
+}
+
+void LLAgentListener::setFollowCamActive(LLSD const & event) const
+{
+ LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, event["active"]);
+}
+
+void LLAgentListener::removeFollowCamParams(LLSD const & event) const
+{
+ LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID);
+}
+
+LLViewerInventoryItem* get_anim_item(LLEventAPI::Response &response, const LLSD &event_data)
+{
+ LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID());
+ if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION))
+ {
+ response.error(stringize("Animation item ", std::quoted(event_data["item_id"].asString()), " was not found"));
+ return NULL;
+ }
+ return item;
+}
+
+void LLAgentListener::playAnimation(LLSD const &event_data)
+{
+ Response response(LLSD(), event_data);
+ if (LLViewerInventoryItem* item = get_anim_item(response, event_data))
+ {
+ mPlayAnimThrottle(item->getAssetUUID(), event_data["inworld"].asBoolean());
+ }
+}
+
+void LLAgentListener::playAnimation_(const LLUUID& asset_id, const bool inworld)
+{
+ if (inworld)
+ {
+ mAgent.sendAnimationRequest(asset_id, ANIM_REQUEST_START);
+ }
+ else
+ {
+ gAgentAvatarp->startMotion(asset_id);
+ }
+}
+
+void LLAgentListener::stopAnimation(LLSD const &event_data)
+{
+ Response response(LLSD(), event_data);
+ if (LLViewerInventoryItem* item = get_anim_item(response, event_data))
+ {
+ gAgentAvatarp->stopMotion(item->getAssetUUID());
+ mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP);
+ }
+}
+
+void LLAgentListener::getAnimationInfo(LLSD const &event_data)
+{
+ Response response(LLSD(), event_data);
+ if (LLViewerInventoryItem* item = get_anim_item(response, event_data))
+ {
+ // if motion exists, will return existing one
+ LLMotion* motion = gAgentAvatarp->createMotion(item->getAssetUUID());
+ response["anim_info"] = llsd::map("duration", motion->getDuration(),
+ "is_loop", motion->getLoop(),
+ "num_joints", motion->getNumJointMotions(),
+ "asset_id", item->getAssetUUID(),
+ "priority", motion->getPriority());
+ }
+}
+
+void LLAgentListener::getID(LLSD const& event_data)
+{
+ Response response(llsd::map("id", gAgentID), event_data);
+}
+
+struct AvResultSet : public LL::ResultSet
+{
+ AvResultSet() : LL::ResultSet("nearby_avatars") {}
+ std::vector<LLVOAvatar*> mAvatars;
+
+ int getLength() const override { return narrow(mAvatars.size()); }
+ LLSD getSingle(int index) const override
+ {
+ auto av = mAvatars[index];
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(av->getID(), &av_name);
+ LLVector3 region_pos = av->getCharacterPosition();
+ return llsd::map("id", av->getID(),
+ "global_pos", ll_sd_from_vector3d(av->getPosGlobalFromAgent(region_pos)),
+ "region_pos", ll_sd_from_vector3(region_pos),
+ "name", av_name.getUserName(),
+ "region_id", av->getRegion()->getRegionID());
+ }
+};
+
+struct ObjResultSet : public LL::ResultSet
+{
+ ObjResultSet() : LL::ResultSet("nearby_objects") {}
+ std::vector<LLViewerObject*> mObjects;
+
+ int getLength() const override { return narrow(mObjects.size()); }
+ LLSD getSingle(int index) const override
+ {
+ auto obj = mObjects[index];
+ return llsd::map("id", obj->getID(),
+ "global_pos", ll_sd_from_vector3d(obj->getPositionGlobal()),
+ "region_pos", ll_sd_from_vector3(obj->getPositionRegion()),
+ "region_id", obj->getRegion()->getRegionID());
+ }
+};
+
+
+F32 get_search_radius(LLSD const& event_data)
+{
+ static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64);
+ F32 dist = render_far_clip;
+ if (event_data.has("dist"))
+ {
+ dist = llclamp((F32)event_data["dist"].asReal(), 1, 512);
+ }
+ return dist * dist;
+}
+
+void LLAgentListener::getNearbyAvatarsList(LLSD const& event_data)
+{
+ Response response(LLSD(), event_data);
+ auto avresult = new AvResultSet;
+
+ F32 radius = get_search_radius(event_data);
+ LLVector3d agent_pos = gAgent.getPositionGlobal();
+ for (LLCharacter* character : LLCharacter::sInstances)
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*)character;
+ if (!avatar->isDead() && !avatar->isControlAvatar() && !avatar->isSelf())
+ {
+ if ((dist_vec_squared(avatar->getPositionGlobal(), agent_pos) <= radius))
+ {
+ avresult->mAvatars.push_back(avatar);
+ }
+ }
+ }
+ response["result"] = avresult->getKeyLength();
+}
+
+void LLAgentListener::getNearbyObjectsList(LLSD const& event_data)
+{
+ Response response(LLSD(), event_data);
+ auto objresult = new ObjResultSet;
+
+ F32 radius = get_search_radius(event_data);
+ S32 num_objects = gObjectList.getNumObjects();
+ LLVector3d agent_pos = gAgent.getPositionGlobal();
+ for (S32 i = 0; i < num_objects; ++i)
+ {
+ LLViewerObject* object = gObjectList.getObject(i);
+ if (object && object->getVolume() && !object->isAttachment())
+ {
+ if ((dist_vec_squared(object->getPositionGlobal(), agent_pos) <= radius))
+ {
+ objresult->mObjects.push_back(object);
+ }
+ }
+ }
+ response["result"] = objresult->getKeyLength();
+}
+
+void LLAgentListener::getAgentScreenPos(LLSD const& event_data)
+{
+ Response response(LLSD(), event_data);
+ LLVector3 render_pos;
+ if (event_data.has("avatar_id") && (event_data["avatar_id"].asUUID() != gAgentID))
+ {
+ LLUUID avatar_id(event_data["avatar_id"]);
+ for (LLCharacter* character : LLCharacter::sInstances)
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*)character;
+ if (!avatar->isDead() && (avatar->getID() == avatar_id))
+ {
+ render_pos = avatar->getRenderPosition();
+ break;
+ }
+ }
+ }
+ else if (gAgentAvatarp.notNull() && gAgentAvatarp->isValid())
+ {
+ render_pos = gAgentAvatarp->getRenderPosition();
+ }
+ LLCoordGL screen_pos;
+ response["onscreen"] = LLViewerCamera::getInstance()->projectPosAgentToScreen(render_pos, screen_pos, false);
+ response["x"] = screen_pos.mX;
+ response["y"] = screen_pos.mY;
+}
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
index c544d089ce..8801c9f7ea 100644
--- a/indra/newview/llagentlistener.h
+++ b/indra/newview/llagentlistener.h
@@ -31,6 +31,7 @@
#define LL_LLAGENTLISTENER_H
#include "lleventapi.h"
+#include "throttle.h"
class LLAgent;
class LLSD;
@@ -48,7 +49,6 @@ private:
void requestStand(LLSD const & event_data) const;
void requestTouch(LLSD const & event_data) const;
void resetAxes(const LLSD& event_data) const;
- void getAxes(const LLSD& event_data) const;
void getGroups(const LLSD& event) const;
void getPosition(const LLSD& event_data) const;
void startAutoPilot(const LLSD& event_data);
@@ -58,11 +58,27 @@ private:
void stopAutoPilot(const LLSD& event_data) const;
void lookAt(LLSD const & event_data) const;
- LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const;
+ void setFollowCamParams(LLSD const & event_data) const;
+ void setFollowCamActive(LLSD const & event_data) const;
+ void removeFollowCamParams(LLSD const & event_data) const;
+
+ void playAnimation(LLSD const &event_data);
+ void playAnimation_(const LLUUID& asset_id, const bool inworld);
+ void stopAnimation(LLSD const &event_data);
+ void getAnimationInfo(LLSD const &event_data);
+
+ void getID(LLSD const& event_data);
+ void getNearbyAvatarsList(LLSD const& event_data);
+ void getNearbyObjectsList(LLSD const& event_data);
+ void getAgentScreenPos(LLSD const& event_data);
+
+ LLViewerObject * findObjectClosestTo( const LLVector3 & position, bool sit_target = false ) const;
private:
LLAgent & mAgent;
LLUUID mFollowTarget;
+
+ LogThrottle<LLError::LEVEL_DEBUG, void(const LLUUID &, const bool)> mPlayAnimThrottle;
};
#endif // LL_LLAGENTLISTENER_H
diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp
index 0b5198bbd3..8b18b7d5a2 100644
--- a/indra/newview/llagentpilot.cpp
+++ b/indra/newview/llagentpilot.cpp
@@ -322,9 +322,7 @@ void LLAgentPilot::moveCamera()
LLViewerCamera::getInstance()->setView(view);
LLViewerCamera::getInstance()->setOrigin(origin);
- LLViewerCamera::getInstance()->mXAxis = LLVector3(mat.mMatrix[0]);
- LLViewerCamera::getInstance()->mYAxis = LLVector3(mat.mMatrix[1]);
- LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]);
+ LLViewerCamera::getInstance()->setAxes(mat);
}
}
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 11c5ffecb6..5114ac8a08 100644
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -839,7 +839,7 @@ void AISAPI::onUpdateReceived(const LLSD& update, COMMAND_TYPE type, const LLSD&
if ( (type == UPDATECATEGORY || type == UPDATEITEM)
&& gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
+ dump_sequential_xml(gAgentAvatarp->getDebugName() + "_ais_update", update);
}
AISUpdate ais_update(update, type, request_body);
diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp
new file mode 100644
index 0000000000..0dab352311
--- /dev/null
+++ b/indra/newview/llappearancelistener.cpp
@@ -0,0 +1,146 @@
+/**
+ * @file llappearancelistener.cpp
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappearancelistener.h"
+
+#include "llappearancemgr.h"
+#include "llinventoryfunctions.h"
+#include "lltransutil.h"
+#include "llwearableitemslist.h"
+#include "stringize.h"
+
+LLAppearanceListener::LLAppearanceListener()
+ : LLEventAPI("LLAppearance",
+ "API to wear a specified outfit and wear/remove individual items")
+{
+ add("wearOutfit",
+ "Wear outfit by folder id: [\"folder_id\"] OR by folder name: [\"folder_name\"]\n"
+ "When [\"append\"] is true, outfit will be added to COF\n"
+ "otherwise it will replace current oufit",
+ &LLAppearanceListener::wearOutfit);
+
+ add("wearItems",
+ "Wear items by id: [items_id]",
+ &LLAppearanceListener::wearItems,
+ llsd::map("items_id", LLSD(), "replace", LLSD()));
+
+ add("detachItems",
+ "Detach items by id: [items_id]",
+ &LLAppearanceListener::detachItems,
+ llsd::map("items_id", LLSD()));
+
+ add("getOutfitsList",
+ "Return the table with Outfits info(id and name)",
+ &LLAppearanceListener::getOutfitsList);
+
+ add("getOutfitItems",
+ "Return the table of items with info(id : name, wearable_type, is_worn) inside specified outfit folder",
+ &LLAppearanceListener::getOutfitItems);
+}
+
+
+void LLAppearanceListener::wearOutfit(LLSD const &data)
+{
+ Response response(LLSD(), data);
+ if (!data.has("folder_id") && !data.has("folder_name"))
+ {
+ return response.error("Either [folder_id] or [folder_name] is required");
+ }
+
+ std::string error_msg;
+ bool result(false);
+ bool append = data.has("append") ? data["append"].asBoolean() : false;
+ if (data.has("folder_id"))
+ {
+ result = LLAppearanceMgr::instance().wearOutfit(data["folder_id"].asUUID(), error_msg, append);
+ }
+ else
+ {
+ result = LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), error_msg, append);
+ }
+
+ if (!result)
+ {
+ response.error(error_msg);
+ }
+}
+
+void LLAppearanceListener::wearItems(LLSD const &data)
+{
+ LLAppearanceMgr::instance().wearItemsOnAvatar(
+ LLSDParam<uuid_vec_t>(data["items_id"]),
+ true, data["replace"].asBoolean());
+}
+
+void LLAppearanceListener::detachItems(LLSD const &data)
+{
+ LLAppearanceMgr::instance().removeItemsFromAvatar(
+ LLSDParam<uuid_vec_t>(data["items_id"]));
+}
+
+void LLAppearanceListener::getOutfitsList(LLSD const &data)
+{
+ Response response(LLSD(), data);
+ const LLUUID outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ LLIsType is_category(LLAssetType::AT_CATEGORY);
+ gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category);
+
+ response["outfits"] = llsd::toMap(cat_array,
+ [](const LLPointer<LLViewerInventoryCategory> &cat)
+ { return std::make_pair(cat->getUUID().asString(), cat->getName()); });
+}
+
+void LLAppearanceListener::getOutfitItems(LLSD const &data)
+{
+ Response response(LLSD(), data);
+ LLUUID outfit_id(data["outfit_id"].asUUID());
+ LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id);
+ if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT)
+ {
+ return response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString()));
+ }
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+
+ LLFindOutfitItems collector = LLFindOutfitItems();
+ gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector);
+
+ response["items"] = llsd::toMap(item_array,
+ [](const LLPointer<LLViewerInventoryItem> &it)
+ {
+ return std::make_pair(
+ it->getUUID().asString(),
+ llsd::map(
+ "name", it->getName(),
+ "wearable_type", LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE),
+ "is_worn", get_is_item_worn(it)));
+ });
+}
diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h
new file mode 100644
index 0000000000..04c5eac2eb
--- /dev/null
+++ b/indra/newview/llappearancelistener.h
@@ -0,0 +1,46 @@
+/**
+ * @file llappearancelistener.h
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLAPPEARANCELISTENER_H
+#define LL_LLAPPEARANCELISTENER_H
+
+#include "lleventapi.h"
+
+class LLAppearanceListener : public LLEventAPI
+{
+public:
+ LLAppearanceListener();
+
+private:
+ void wearOutfit(LLSD const &data);
+ void wearItems(LLSD const &data);
+ void detachItems(LLSD const &data);
+ void getOutfitsList(LLSD const &data);
+ void getOutfitItems(LLSD const &data);
+};
+
+#endif // LL_LLAPPEARANCELISTENER_H
+
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 946d674e8b..eae5aa36e0 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -31,6 +31,7 @@
#include "llagent.h"
#include "llagentcamera.h"
#include "llagentwearables.h"
+#include "llappearancelistener.h"
#include "llappearancemgr.h"
#include "llattachmentsmgr.h"
#include "llcommandhandler.h"
@@ -48,6 +49,7 @@
#include "lloutfitslist.h"
#include "llselectmgr.h"
#include "llsidepanelappearance.h"
+#include "lltransutil.h"
#include "llviewerobjectlist.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
@@ -66,6 +68,8 @@
#include "llavatarpropertiesprocessor.h"
+LLAppearanceListener sAppearanceListener;
+
namespace
{
const S32 BAKE_RETRY_MAX_COUNT = 5;
@@ -113,26 +117,16 @@ public:
LLOutfitUnLockTimer(F32 period) : LLEventTimer(period)
{
// restart timer on BOF changed event
- LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(
- &LLOutfitUnLockTimer::reset, this));
+ LLOutfitObserver::instance().addBOFChangedCallback([this]{ start(); });
stop();
}
- /*virtual*/
- bool tick()
+ bool tick() override
{
- if(mEventTimer.hasExpired())
- {
- LLAppearanceMgr::instance().setOutfitLocked(false);
- }
+ LLAppearanceMgr::instance().setOutfitLocked(false);
return false;
}
- void stop() { mEventTimer.stop(); }
- void start() { mEventTimer.start(); }
- void reset() { mEventTimer.reset(); }
- bool getStarted() { return mEventTimer.getStarted(); }
-
- LLTimer& getEventTimer() { return mEventTimer;}
+ bool getStarted() { return isRunning(); }
};
// support for secondlife:///app/appearance SLapps
@@ -327,7 +321,7 @@ public:
// virtual
// Will be deleted after returning true - only safe to do this if all callbacks have fired.
- bool tick()
+ bool tick() override
{
// mPendingRequests will be zero if all requests have been
// responded to. mWaitTimes.empty() will be true if we have
@@ -620,8 +614,8 @@ void LLBrokenLinkObserver::changed(U32 mask)
if (id == mUUID)
{
// Might not be processed yet and it is not a
- // good idea to update appearane here, postpone.
- doOnIdleOneTime([this]()
+ // good idea to update appearance here, postpone.
+ doOnIdleOneTime([this]
{
postProcess();
});
@@ -1707,7 +1701,6 @@ void LLAppearanceMgr::setOutfitLocked(bool locked)
mOutfitLocked = locked;
if (locked)
{
- mUnlockOutfitTimer->reset();
mUnlockOutfitTimer->start();
}
else
@@ -2037,7 +2030,7 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
}
// Moved from LLWearableList::ContextMenu for wider utility.
-bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) const
+bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismatch) const
{
// TODO: investigate wearables may not be loaded at this point EXT-8231
@@ -2067,7 +2060,10 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) const
}
else
{
- LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
+ if (warn_on_type_mismatch)
+ {
+ LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
+ }
return false;
}
}
@@ -2258,7 +2254,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
}
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents);
+ dump_sequential_xml(gAgentAvatarp->getDebugName() + "_slam_request", contents);
}
slam_inventory_folder(getCOF(), contents, link_waiter);
@@ -2906,8 +2902,18 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
LLAppearanceMgr::changeOutfit(true, category->getUUID(), append);
}
-// FIXME do we really want to search entire inventory for matching name?
-void LLAppearanceMgr::wearOutfitByName(const std::string& name)
+bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append)
+{
+ std::string error_msg;
+ if(!wearOutfitByName(name, error_msg, append))
+ {
+ LL_WARNS() << error_msg << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+bool LLAppearanceMgr::wearOutfitByName(const std::string& name, std::string& error_msg, bool append)
{
LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL;
@@ -2940,15 +2946,38 @@ void LLAppearanceMgr::wearOutfitByName(const std::string& name)
}
}
- if(cat)
+ return wearOutfit(stringize(std::quoted(name)), cat, error_msg, copy_items, append);
+}
+
+bool LLAppearanceMgr::wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append)
+{
+ LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ return wearOutfit(stringize(cat_id), cat, error_msg, false, append);
+}
+
+bool LLAppearanceMgr::wearOutfit(const std::string &desc, LLInventoryCategory* cat,
+ std::string &error_msg, bool copy_items, bool append)
+{
+ if (!cat)
{
- LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false);
+ error_msg = stringize(LLTrans::getString("OutfitNotFound"), desc);
+ return false;
}
- else
+ // don't allow wearing a system folder
+ if (LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+ {
+ error_msg = stringize(LLTrans::getString("SystemFolderNotWorn"), std::quoted(cat->getName()));
+ return false;
+ }
+ bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID());
+ if (!can_wear)
{
- LL_WARNS() << "Couldn't find outfit " <<name<< " in wearOutfitByName()"
- << LL_ENDL;
+ std::string msg = append ? LLTrans::getString("OutfitNotAdded") : LLTrans::getString("OutfitNotReplaced");
+ error_msg = stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID());
+ return false;
}
+ wearInventoryCategory(cat, copy_items, append);
+ return true;
}
bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b)
@@ -3951,7 +3980,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd
LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", result);
+ dump_sequential_xml(gAgentAvatarp->getDebugName() + "_appearance_request_ok", result);
}
} while (bRetry);
@@ -3960,7 +3989,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd
/*static*/
void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content)
{
- dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
+ dump_sequential_xml(gAgentAvatarp->getDebugName() + "_appearance_request_error", content);
LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
<< " ================================= " << LL_ENDL;
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 6c45a32856..acb4d6174f 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -59,7 +59,9 @@ public:
void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append);
- void wearOutfitByName(const std::string& name);
+ bool wearOutfit(const LLUUID &cat_id, std::string &error_msg, bool append = false);
+ bool wearOutfitByName(const std::string &name, std::string &error_msg, bool append = false);
+ bool wearOutfitByName(const std::string &name, bool append = false);
void changeOutfit(bool proceed, const LLUUID& category, bool append);
void replaceCurrentOutfit(const LLUUID& new_outfit);
void renameOutfit(const LLUUID& outfit_id);
@@ -102,7 +104,7 @@ public:
bool getCanReplaceCOF(const LLUUID& outfit_cat_id);
// Can we add all referenced items to the avatar?
- bool canAddWearables(const uuid_vec_t& item_ids) const;
+ bool canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismatch = true) const;
// Copy all items in a category.
void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
@@ -261,6 +263,10 @@ private:
static void onOutfitRename(const LLSD& notification, const LLSD& response);
+ // used by both wearOutfit(LLUUID) and wearOutfitByName(std::string)
+ bool wearOutfit(const std::string &desc, LLInventoryCategory* cat,
+ std::string &error_msg, bool copy_items, bool append);
+
bool mAttachmentInvLinkEnabled;
bool mOutfitIsDirty;
bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls.
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 41cd05f828..aa95681d32 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -29,6 +29,7 @@
#include "llappviewer.h"
// Viewer includes
+#include "coro_scheduler.h"
#include "llversioninfo.h"
#include "llfeaturemanager.h"
#include "lluictrlfactory.h"
@@ -46,6 +47,7 @@
#include "llagentwearables.h"
#include "lldirpicker.h"
#include "llfloaterimcontainer.h"
+#include "llfloaterpreference.h"
#include "llimprocessing.h"
#include "llwindow.h"
#include "llviewerstats.h"
@@ -60,8 +62,10 @@
#include "llslurl.h"
#include "llstartup.h"
#include "llfocusmgr.h"
+#include "llluamanager.h"
#include "llurlfloaterdispatchhandler.h"
#include "llviewerjoystick.h"
+#include "llgamecontrol.h"
#include "llcalc.h"
#include "llconversationlog.h"
#if LL_WINDOWS
@@ -111,10 +115,12 @@
#include "llgltfmateriallist.h"
// Linden library includes
+#include "fsyspath.h"
#include "llavatarnamecache.h"
#include "lldiriterator.h"
#include "llexperiencecache.h"
#include "llimagej2c.h"
+#include "llluamanager.h"
#include "llmemory.h"
#include "llprimitive.h"
#include "llurlaction.h"
@@ -137,11 +143,7 @@
#include "vlc/libvlc_version.h"
#if LL_DARWIN
-#if LL_SDL
-#include "llwindowsdl.h"
-#else
#include "llwindowmacosx.h"
-#endif // LL_SDL
#endif
// Third party library includes
@@ -184,7 +186,6 @@
#include "lltracker.h"
#include "llviewerparcelmgr.h"
#include "llworldmapview.h"
-#include "llpostprocess.h"
#include "lldebugview.h"
#include "llconsole.h"
@@ -215,12 +216,12 @@
#include "llvosurfacepatch.h"
#include "llviewerfloaterreg.h"
#include "llcommandlineparser.h"
+#include "llfloaterpreference.h"
#include "llfloatermemleak.h"
#include "llfloaterreg.h"
#include "llfloatersimplesnapshot.h"
#include "llfloatersnapshot.h"
#include "llsidepanelinventory.h"
-#include "llatmosphere.h"
// includes for idle() idleShutdown()
#include "llviewercontrol.h"
@@ -255,6 +256,9 @@ using namespace LL;
#include "llviewereventrecorder.h"
#include <chrono>
+#include "rlvactions.h"
+#include "rlvcommon.h"
+#include "rlvhandler.h"
// *FIX: These extern globals should be cleaned up.
// The globals either represent state/config/resource-storage of either
@@ -270,10 +274,9 @@ using namespace LL;
// define a self-registering event API object
#include "llappviewerlistener.h"
-#if LL_MSVC
-// disable boost::lexical_cast warning
-#pragma warning (disable:4702)
-#endif
+#if LL_LINUX && LL_GTK
+#include "glib.h"
+#endif // (LL_LINUX) && LL_GTK
static LLAppViewerListener sAppViewerListener(LLAppViewer::instance);
@@ -389,6 +392,8 @@ static std::string gLaunchFileOnQuit;
// Used on Win32 for other apps to identify our window (eg, win_setup)
const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
+void processComposeSwitch(const std::string&, const std::string&,
+ const std::function<void(const LLSD&)>&);
//----------------------------------------------------------------------------
@@ -459,11 +464,20 @@ void idle_afk_check()
{
// check idle timers
F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32();
- F32 afk_timeout = (F32)gSavedSettings.getS32("AFKTimeout");
- if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK())
+ LLCachedControl<S32> afk_timeout(gSavedSettings, "AFKTimeout", 300);
+ if (afk_timeout() && (current_idle > afk_timeout()))
{
- LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
- gAgent.setAFK();
+ if (!gAgent.getAFK())
+ {
+ LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
+ gAgent.setAFK();
+ }
+ else
+ {
+ // Refresh timer so that random one click or hover won't clear the status.
+ // But expanding the window still should lift afk status
+ gAwayTimer.reset();
+ }
}
}
@@ -566,11 +580,7 @@ static void settings_to_globals()
LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale"));
#if LL_DARWIN
-#if LL_SDL
- LLWindowSDL::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL");
-#else
LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL");
-#endif // LL_SDL
gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI");
#endif
}
@@ -771,6 +781,8 @@ bool LLAppViewer::init()
//set the max heap size.
initMaxHeapSize() ;
LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize"));
+ // Use our custom scheduler for coroutine scheduling.
+ llcoro::scheduler::use();
// Although initLoggingAndGetLastDuration() is the right place to mess with
// setFatalFunction(), we can't query gSavedSettings until after
@@ -1144,6 +1156,15 @@ bool LLAppViewer::init()
LLViewerJoystick::getInstance()->init(false);
}
+ LLGameControl::init(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "gamecontrollerdb.txt"),
+ [&](const std::string& name) -> bool { return gSavedSettings.getBOOL(name); },
+ [&](const std::string& name, bool value) { gSavedSettings.setBOOL(name, value); },
+ [&](const std::string& name) -> std::string { return gSavedSettings.getString(name); },
+ [&](const std::string& name, const std::string& value) { gSavedSettings.setString(name, value); },
+ [&](const std::string& name) -> LLSD { return gSavedSettings.getLLSD(name); },
+ [&](const std::string& name, const LLSD& value) { gSavedSettings.setLLSD(name, value); },
+ [&]() { LLPanelPreferenceGameControl::updateDeviceList(); });
+
try
{
initializeSecHandler();
@@ -1218,22 +1239,10 @@ bool LLAppViewer::init()
}
#endif //LL_RELEASE_FOR_DOWNLOAD
- {
- // Iterate over --leap command-line options. But this is a bit tricky: if
- // there's only one, it won't be an array at all.
- LLSD LeapCommand(gSavedSettings.getLLSD("LeapCommand"));
- LL_DEBUGS("InitInfo") << "LeapCommand: " << LeapCommand << LL_ENDL;
- if (LeapCommand.isDefined() && !LeapCommand.isArray())
- {
- // If LeapCommand is actually a scalar value, make an array of it.
- // Have to do it in two steps because LeapCommand.append(LeapCommand)
- // trashes content! :-P
- LLSD item(LeapCommand);
- LeapCommand.append(item);
- }
- for (const auto& leap : llsd::inArray(LeapCommand))
+ processComposeSwitch(
+ "--leap", "LeapCommand",
+ [](const LLSD& leap)
{
- LL_INFOS("InitInfo") << "processing --leap \"" << leap << '"' << LL_ENDL;
// We don't have any better description of this plugin than the
// user-specified command line. Passing "" causes LLLeap to derive a
// description from the command line itself.
@@ -1241,8 +1250,40 @@ bool LLAppViewer::init()
// don't consider any one --leap command mission-critical, so if one
// fails, log it, shrug and carry on.
LLLeap::create("", leap, false); // exception=false
- }
- }
+ });
+ processComposeSwitch(
+ "--lua", "LuaChunk",
+ [](const LLSD& chunk)
+ {
+ // no completion callback: we don't need to know
+ LLLUAmanager::runScriptLine(chunk);
+ });
+ processComposeSwitch(
+ "--luafile", "LuaScript",
+ [](const LLSD& script)
+ {
+ // no completion callback: we don't need to know
+ LLLUAmanager::runScriptFile(script);
+ });
+ processComposeSwitch(
+ "LuaAutorunPath", "LuaAutorunPath",
+ [](const LLSD& directory)
+ {
+ // each directory can be relative to the viewer's install
+ // directory -- if directory is already absolute, operator/()
+ // preserves it
+ fsyspath abspath(fsyspath(gDirUtilp->getAppRODataDir()) /
+ fsyspath(directory.asString()));
+ std::string absdir(fsyspath(abspath).string());
+ LL_DEBUGS("InitInfo") << "LuaAutorunPath: " << absdir << LL_ENDL;
+ LLDirIterator scripts(absdir, "*.lua");
+ std::string script;
+ while (scripts.next(script))
+ {
+ LL_DEBUGS("InitInfo") << "LuaAutorunPath: " << absdir << ": " << script << LL_ENDL;
+ LLLUAmanager::runScriptFile(fsyspath(abspath / fsyspath(script)).string(), true);
+ }
+ });
if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
{
@@ -1318,6 +1359,27 @@ bool LLAppViewer::init()
return true;
}
+void processComposeSwitch(const std::string& option,
+ const std::string& setting,
+ const std::function<void(const LLSD&)>& action)
+{
+ // Iterate over 'option' command-line options. But this is a bit tricky:
+ // if there's only one, it won't be an array at all.
+ LLSD args(gSavedSettings.getLLSD(setting));
+ LL_DEBUGS("InitInfo") << option << ": " << args << LL_ENDL;
+ if (args.isDefined() && ! args.isArray())
+ {
+ // If args is actually a scalar value, make an array of it. Have to do
+ // it in two steps because args.append(args) trashes content! :-P
+ args.append(LLSD(args));
+ }
+ for (const auto& arg : llsd::inArray(args))
+ {
+ LL_INFOS("InitInfo") << "processing " << option << ' ' << arg << LL_ENDL;
+ action(arg);
+ }
+}
+
void LLAppViewer::initMaxHeapSize()
{
//set the max heap size.
@@ -1386,6 +1448,48 @@ bool LLAppViewer::frame()
return ret;
}
+void sendGameControlInput()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ const LLGameControl::State& state = LLGameControl::getState();
+
+ msg->newMessageFast(_PREHASH_GameControlInput);
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgentID);
+ msg->addUUID("SessionID", gAgentSessionID);
+
+ size_t num_indices = state.mAxes.size();
+ for (U8 i = 0; i < num_indices; ++i)
+ {
+ if (state.mAxes[i] != state.mPrevAxes[i])
+ {
+ // only pack an axis if it differs from previously packed value
+ msg->nextBlockFast(_PREHASH_AxisData);
+ msg->addU8Fast(_PREHASH_Index, i);
+ msg->addS16Fast(_PREHASH_Value, state.mAxes[i]);
+ }
+ }
+
+ U32 button_flags = state.mButtons;
+ if (button_flags > 0)
+ {
+ std::vector<U8> buttons;
+ for (U8 i = 0; i < 32; i++)
+ {
+ if (button_flags & (0x1 << i))
+ {
+ buttons.push_back(i);
+ }
+ }
+ msg->nextBlockFast(_PREHASH_ButtonData);
+ msg->addBinaryDataFast(_PREHASH_Data, (void*)(buttons.data()), (S32)(buttons.size()));
+ }
+
+ LLGameControl::updateResendPeriod();
+ gAgent.sendMessage();
+}
+
+
bool LLAppViewer::doFrame()
{
static LLCachedControl<U32> fpsLimitMaxFps(gSavedSettings, "MaxFPS", 0);
@@ -1454,7 +1558,7 @@ bool LLAppViewer::doFrame()
LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
}
- gViewerWindow->getWindow()->gatherInput();
+ gViewerWindow->getWindow()->gatherInput(gFocusMgr.getAppHasFocus());
}
//memory leaking simulation
@@ -1755,11 +1859,12 @@ void LLAppViewer::flushLFSIO()
bool LLAppViewer::cleanup()
{
- LLAtmosphere::cleanupClass();
-
//ditch LLVOAvatarSelf instance
gAgentAvatarp = NULL;
+ // Sanity check to catch cases where someone forgot to do an RlvActions::isRlvEnabled() check
+ LL_ERRS_IF(!RlvHandler::isEnabled() && RlvHandler::instanceExists()) << "RLV handler instance exists even though RLVa is disabled" << LL_ENDL;
+
LLNotifications::instance().clear();
// workaround for DEV-35406 crash on shutdown
@@ -1928,44 +2033,12 @@ bool LLAppViewer::cleanup()
// Clean up before GL is shut down because we might be holding on to objects with texture references
LLSelectMgr::cleanupGlobals();
- LL_INFOS() << "Shutting down OpenGL" << LL_ENDL;
-
- // Shut down OpenGL
- if( gViewerWindow)
- {
- gViewerWindow->shutdownGL();
-
- // Destroy window, and make sure we're not fullscreen
- // This may generate window reshape and activation events.
- // Therefore must do this before destroying the message system.
- delete gViewerWindow;
- gViewerWindow = NULL;
- LL_INFOS() << "ViewerWindow deleted" << LL_ENDL;
- }
-
- LLSplashScreen::show();
- LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
-
- LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL;
-
- // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
- delete gKeyboard;
- gKeyboard = NULL;
-
- if (LLViewerJoystick::instanceExists())
- {
- // Turn off Space Navigator and similar devices
- LLViewerJoystick::getInstance()->terminate();
- }
-
LL_INFOS() << "Cleaning up Objects" << LL_ENDL;
LLViewerObject::cleanupVOClasses();
SUBSYSTEM_CLEANUP(LLAvatarAppearance);
- SUBSYSTEM_CLEANUP(LLPostProcess);
-
LLTracker::cleanupInstance();
// *FIX: This is handled in LLAppViewerWin32::cleanup().
@@ -2118,6 +2191,37 @@ bool LLAppViewer::cleanup()
sTextureFetch->shutDownTextureCacheThread() ;
LLLFSThread::sLocal->shutdown();
+ LL_INFOS() << "Shutting down OpenGL" << LL_ENDL;
+
+ // Shut down OpenGL
+ if (gViewerWindow)
+ {
+ gViewerWindow->shutdownGL();
+
+ // Destroy window, and make sure we're not fullscreen
+ // This may generate window reshape and activation events.
+ // Therefore must do this before destroying the message system.
+ delete gViewerWindow;
+ gViewerWindow = NULL;
+ LL_INFOS() << "ViewerWindow deleted" << LL_ENDL;
+ }
+
+ LLSplashScreen::show();
+ LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
+
+ LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL;
+
+ // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
+ delete gKeyboard;
+ gKeyboard = NULL;
+
+ if (LLViewerJoystick::instanceExists())
+ {
+ // Turn off Space Navigator and similar devices
+ LLViewerJoystick::getInstance()->terminate();
+ }
+ LLGameControl::terminate();
+
LL_INFOS() << "Shutting down message system" << LL_ENDL;
end_messaging_system();
@@ -2855,6 +2959,14 @@ bool LLAppViewer::initConfiguration()
gSavedSettings.setBOOL("RenderDebugGLSession", false);
}
+ if (gSavedSettings.getBOOL("RenderDebugTextureLabelLocalFilesSession"))
+ {
+ gDebugTextureLabelLocalFilesSession = true;
+ // Texture label accounting for local files takes up memory in the
+ // background, so don't persist.
+ gSavedSettings.setBOOL("RenderDebugTextureLabelLocalFilesSession", false);
+ }
+
const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
if (skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
{
@@ -3391,6 +3503,7 @@ LLSD LLAppViewer::getViewerInfo() const
}
#endif
+ info["RLV_VERSION"] = RlvActions::isRlvEnabled() ? Rlv::Strings::getVersionAbout() : "(disabled)";
info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION)));
// Settings
@@ -3436,7 +3549,6 @@ LLSD LLAppViewer::getViewerInfo() const
info["VOICE_VERSION"] = LLTrans::getString("NotConnected");
}
-#if LL_DARWIN || LL_LINUX || __FreeBSD__
std::ostringstream cef_ver_codec;
cef_ver_codec << "Dullahan: ";
cef_ver_codec << DULLAHAN_VERSION_MAJOR;
@@ -3462,9 +3574,6 @@ LLSD LLAppViewer::getViewerInfo() const
cef_ver_codec << CHROME_VERSION_PATCH;
info["LIBCEF_VERSION"] = cef_ver_codec.str();
-#else
- info["LIBCEF_VERSION"] = "Undefined";
-#endif
//#if !LL_LINUX
std::ostringstream vlc_ver_codec;
@@ -4657,7 +4766,6 @@ void LLAppViewer::idle()
LLFrameTimer::updateFrameTime();
LLFrameTimer::updateFrameCount();
- LLEventTimer::updateClass();
LLPerfStats::updateClass();
// LLApp::stepFrame() performs the above three calls plus mRunner.run().
@@ -4761,6 +4869,30 @@ void LLAppViewer::idle()
gAgent.autoPilot(&yaw);
}
+ // get control flags from each side
+ U32 control_flags = gAgent.getControlFlags();
+ U32 game_control_action_flags = LLGameControl::computeInternalActionFlags();
+
+ // apply to GameControl
+ LLGameControl::setExternalInput(control_flags, gAgent.getGameControlButtonsFromKeys());
+ bool should_send_game_control = LLGameControl::computeFinalStateAndCheckForChanges();
+ if (LLPanelPreferenceGameControl::isWaitingForInputChannel())
+ {
+ LLPanelPreferenceGameControl::applyGameControlInput();
+ // skip this send because input is being used to set preferences
+ should_send_game_control = false;
+ }
+ if (should_send_game_control)
+ {
+ sendGameControlInput();
+ }
+
+ // apply to AvatarControl
+ if (LLGameControl::isEnabled() && LLGameControl::willControlAvatar())
+ {
+ gAgent.applyExternalActionFlags(game_control_action_flags);
+ }
+
send_agent_update(false);
// After calling send_agent_update() in the mainloop we always clear
@@ -5018,6 +5150,10 @@ void LLAppViewer::idle()
{
LLViewerJoystick::getInstance()->moveFlycam();
}
+ else if (gAgent.isUsingFlycam())
+ {
+ gAgent.updateFlycam();
+ }
else
{
if (LLToolMgr::getInstance()->inBuildMode())
@@ -5593,9 +5729,9 @@ void LLAppViewer::forceErrorThreadCrash()
thread->start();
}
-void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
+void LLAppViewer::initMainloopTimeout(std::string_view state, F32 secs)
{
- if(!mMainloopTimeout)
+ if (!mMainloopTimeout)
{
mMainloopTimeout = new LLWatchdogTimeout();
resumeMainloopTimeout(state, secs);
@@ -5604,20 +5740,20 @@ void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
void LLAppViewer::destroyMainloopTimeout()
{
- if(mMainloopTimeout)
+ if (mMainloopTimeout)
{
delete mMainloopTimeout;
- mMainloopTimeout = NULL;
+ mMainloopTimeout = nullptr;
}
}
-void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
+void LLAppViewer::resumeMainloopTimeout(std::string_view state, F32 secs)
{
- if(mMainloopTimeout)
+ if (mMainloopTimeout)
{
- if(secs < 0.0f)
+ if (secs < 0.0f)
{
- static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
+ static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60.f);
secs = mainloop_timeout;
}
@@ -5628,19 +5764,19 @@ void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
void LLAppViewer::pauseMainloopTimeout()
{
- if(mMainloopTimeout)
+ if (mMainloopTimeout)
{
mMainloopTimeout->stop();
}
}
-void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
+void LLAppViewer::pingMainloopTimeout(std::string_view state, F32 secs)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
- if(mMainloopTimeout)
+ if (mMainloopTimeout)
{
- if(secs < 0.0f)
+ if (secs < 0.0f)
{
static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
secs = mainloop_timeout;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 4ce4259ed8..6e02869fba 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -183,11 +183,11 @@ public:
// For thread debugging.
// llstartup needs to control init.
// llworld, send_agent_pause() also controls pause/resume.
- void initMainloopTimeout(const std::string& state, F32 secs = -1.0f);
+ void initMainloopTimeout(std::string_view state, F32 secs = -1.0f);
void destroyMainloopTimeout();
void pauseMainloopTimeout();
- void resumeMainloopTimeout(const std::string& state = "", F32 secs = -1.0f);
- void pingMainloopTimeout(const std::string& state, F32 secs = -1.0f);
+ void resumeMainloopTimeout(std::string_view state = "", F32 secs = -1.0f);
+ void pingMainloopTimeout(std::string_view state, F32 secs = -1.0f);
// Handle the 'login completed' event.
// *NOTE:Mani Fix this for login abstraction!!
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index c1e8f38c51..9506ccad60 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -71,8 +71,7 @@ extern "C"
#include "breakpad/common/linux/http_upload.h"
#include "lldir.h"
#include "../llcrashlogger/llcrashlogger.h"
-#include "jsoncpp/reader.h" // JSON
-
+#include "boost/json.hpp"
#endif
#define VIEWERAPI_SERVICE "com.secondlife.ViewerAppAPIService"
@@ -135,7 +134,7 @@ int main( int argc, char **argv )
return -1;
}
- // Run the application main loop
+ // Run the application main loop
while (! viewer_app_ptr->frame())
{}
@@ -186,26 +185,28 @@ void setupBreadpad()
return;
}
- Json::Reader reader;
- Json::Value build_data;
- if(!reader.parse(inf, build_data, false))
+ boost::json::error_code ec;
+ boost::json::value build_data = boost::json::parse(inf, ec);
+ if(ec.failed())
{
LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': "
- << reader.getFormatedErrorMessages() << LL_ENDL;
+ << ec.what() << LL_ENDL;
return;
}
- Json::Value BugSplat_DB = build_data["BugSplat DB"];
- if(!BugSplat_DB)
+ if (!build_data.is_object() || !build_data.as_object().contains("BugSplat DB"))
{
LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" << build_data_fname
<< "'" << LL_ENDL;
return;
}
+
gVersion = STRINGIZE(
LL_VIEWER_VERSION_MAJOR << '.' << LL_VIEWER_VERSION_MINOR << '.' << LL_VIEWER_VERSION_PATCH
<< '.' << LL_VIEWER_VERSION_BUILD);
- gBugsplatDB = BugSplat_DB.asString();
+
+ boost::json::value BugSplat_DB = build_data.at("BugSplat DB");
+ gBugsplatDB = boost::json::value_to<std::string>(BugSplat_DB);
LL_INFOS("BUGSPLAT") << "Initializing with crash logger: " << gCrashLogger << " database: " << gBugsplatDB << " version: " << gVersion << LL_ENDL;
diff --git a/indra/newview/llappviewerlistener.cpp b/indra/newview/llappviewerlistener.cpp
index 6d519b6fef..4690c91b61 100644
--- a/indra/newview/llappviewerlistener.cpp
+++ b/indra/newview/llappviewerlistener.cpp
@@ -35,6 +35,7 @@
// external library headers
// other Linden headers
#include "llappviewer.h"
+#include "workqueue.h"
LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter):
LLEventAPI("LLAppViewer",
@@ -42,6 +43,9 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter):
mAppViewerGetter(getter)
{
// add() every method we want to be able to invoke via this event API.
+ add("userQuit",
+ "Ask to quit with user confirmation prompt",
+ &LLAppViewerListener::userQuit);
add("requestQuit",
"Ask to quit nicely",
&LLAppViewerListener::requestQuit);
@@ -50,14 +54,26 @@ LLAppViewerListener::LLAppViewerListener(const LLAppViewerGetter& getter):
&LLAppViewerListener::forceQuit);
}
+void LLAppViewerListener::userQuit(const LLSD& event)
+{
+ LL_INFOS() << "Listener requested user quit" << LL_ENDL;
+ // Trying to engage this from (e.g.) a Lua-hosting C++ coroutine runs
+ // afoul of an assert in the logging machinery that LLMutex must be locked
+ // only from the main coroutine.
+ LL::WorkQueue::getInstance("mainloop")->post(
+ [appviewer=mAppViewerGetter()]{ appviewer->userQuit(); });
+}
+
void LLAppViewerListener::requestQuit(const LLSD& event)
{
LL_INFOS() << "Listener requested quit" << LL_ENDL;
- mAppViewerGetter()->requestQuit();
+ LL::WorkQueue::getInstance("mainloop")->post(
+ [appviewer=mAppViewerGetter()]{ appviewer->requestQuit(); });
}
void LLAppViewerListener::forceQuit(const LLSD& event)
{
LL_INFOS() << "Listener requested force quit" << LL_ENDL;
- mAppViewerGetter()->forceQuit();
+ LL::WorkQueue::getInstance("mainloop")->post(
+ [appviewer=mAppViewerGetter()]{ appviewer->forceQuit(); });
}
diff --git a/indra/newview/llappviewerlistener.h b/indra/newview/llappviewerlistener.h
index 5ade3d3e04..e116175eb7 100644
--- a/indra/newview/llappviewerlistener.h
+++ b/indra/newview/llappviewerlistener.h
@@ -30,7 +30,7 @@
#define LL_LLAPPVIEWERLISTENER_H
#include "lleventapi.h"
-#include <boost/function.hpp>
+#include <functional>
class LLAppViewer;
class LLSD;
@@ -39,11 +39,12 @@ class LLSD;
class LLAppViewerListener: public LLEventAPI
{
public:
- typedef boost::function<LLAppViewer*(void)> LLAppViewerGetter;
+ typedef std::function<LLAppViewer*(void)> LLAppViewerGetter;
/// Bind the LLAppViewer instance to use (e.g. LLAppViewer::instance()).
LLAppViewerListener(const LLAppViewerGetter& getter);
private:
+ void userQuit(const LLSD& event);
void requestQuit(const LLSD& event);
void forceQuit(const LLSD& event);
diff --git a/indra/newview/llautoreplace.cpp b/indra/newview/llautoreplace.cpp
index f200ca8e31..1ea2899ba4 100644
--- a/indra/newview/llautoreplace.cpp
+++ b/indra/newview/llautoreplace.cpp
@@ -536,11 +536,12 @@ LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::replaceList(const LL
S32 search_index;
LLSD targetList;
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
- for ( search_index = 0, targetList = mLists[0];
+ for ( search_index = 0;
!listFound && search_index < mLists.size();
- search_index += 1, targetList = mLists[search_index]
+ search_index += 1
)
{
+ targetList = mLists[search_index];
if ( targetList.isMap() )
{
if ( listNameMatches( targetList, listName) )
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 6f6b89ea81..aff959d279 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -285,25 +285,18 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floate
make_ui_sound("UISndStartIM");
}
-/* AD *TODO: Is this function needed any more?
- I fixed it a bit(added check for canCall), but it appears that it is not used
- anywhere. Maybe it should be removed?
// static
-bool LLAvatarActions::isCalling(const LLUUID &id)
+bool LLAvatarActions::canCall()
{
- if (id.isNull() || !canCall())
- {
- return false;
- }
-
- LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id);
- return (LLIMModel::getInstance()->findIMSession(session_id) != NULL);
-}*/
+ LLVoiceClient* voice_client = LLVoiceClient::getInstance();
+ return voice_client->voiceEnabled() && voice_client->isVoiceWorking();
+}
-//static
-bool LLAvatarActions::canCall()
+// static
+bool LLAvatarActions::canCallTo(const LLUUID& id)
{
- return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
+ LLVoiceClient* voice_client = LLVoiceClient::getInstance();
+ return voice_client->voiceEnabled() && voice_client->isVoiceWorking() && voice_client->getVoiceEnabled(id);
}
// static
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 1f5a42ed22..6f469e96ce 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -172,18 +172,15 @@ public:
static bool canBlock(const LLUUID& id);
/**
- * Return true if the avatar is in a P2P voice call with a given user
+ * @return true if voice calls are available
*/
- /* AD *TODO: Is this function needed any more?
- I fixed it a bit(added check for canCall), but it appears that it is not used
- anywhere. Maybe it should be removed?
- static bool isCalling(const LLUUID &id);*/
+ static bool canCall();
/**
* @return true if call to the resident can be made
*/
+ static bool canCallTo(const LLUUID& id);
- static bool canCall();
/**
* Invite avatar to a group.
*/
diff --git a/indra/newview/llblocklist.cpp b/indra/newview/llblocklist.cpp
index 89516a8a84..bb1e3405d7 100644
--- a/indra/newview/llblocklist.cpp
+++ b/indra/newview/llblocklist.cpp
@@ -50,7 +50,7 @@ LLBlockList::LLBlockList(const Params& p)
mMuteListSize = static_cast<U32>(LLMuteList::getInstance()->getMutes().size());
// Set up context menu.
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
registrar.add ("Block.Action", boost::bind(&LLBlockList::onCustomAction, this, _2));
diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp
deleted file mode 100644
index c474f2885b..0000000000
--- a/indra/newview/llcallbacklist.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/**
- * @file llcallbacklist.cpp
- * @brief A simple list of callback functions to call.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llcallbacklist.h"
-#include "lleventtimer.h"
-
-// Library includes
-#include "llerror.h"
-
-
-//
-// Globals
-//
-LLCallbackList gIdleCallbacks;
-
-//
-// Member functions
-//
-
-LLCallbackList::LLCallbackList()
-{
- // nothing
-}
-
-LLCallbackList::~LLCallbackList()
-{
-}
-
-
-void LLCallbackList::addFunction( callback_t func, void *data)
-{
- if (!func)
- {
- LL_ERRS() << "LLCallbackList::addFunction - function is NULL" << LL_ENDL;
- return;
- }
-
- // only add one callback per func/data pair
- callback_pair_t t(func, data);
- callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t);
- if (iter == mCallbackList.end())
- {
- mCallbackList.push_back(t);
- }
-}
-
-
-BOOL LLCallbackList::containsFunction( callback_t func, void *data)
-{
- callback_pair_t t(func, data);
- callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t);
- if (iter != mCallbackList.end())
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-
-BOOL LLCallbackList::deleteFunction( callback_t func, void *data)
-{
- callback_pair_t t(func, data);
- callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t);
- if (iter != mCallbackList.end())
- {
- mCallbackList.erase(iter);
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-
-void LLCallbackList::deleteAllFunctions()
-{
- mCallbackList.clear();
-}
-
-
-void LLCallbackList::callFunctions()
-{
- for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- curiter->first(curiter->second);
- }
-}
-
-// Shim class to allow arbitrary boost::bind
-// expressions to be run as one-time idle callbacks.
-class OnIdleCallbackOneTime
-{
-public:
- OnIdleCallbackOneTime(nullary_func_t callable):
- mCallable(callable)
- {
- }
- static void onIdle(void *data)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
- self->call();
- delete self;
- }
- void call()
- {
- mCallable();
- }
-private:
- nullary_func_t mCallable;
-};
-
-void doOnIdleOneTime(nullary_func_t callable)
-{
- OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
-}
-
-// Shim class to allow generic boost functions to be run as
-// recurring idle callbacks. Callable should return true when done,
-// false to continue getting called.
-class OnIdleCallbackRepeating
-{
-public:
- OnIdleCallbackRepeating(bool_func_t callable):
- mCallable(callable)
- {
- }
- // Will keep getting called until the callable returns true.
- static void onIdle(void *data)
- {
- OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
- bool done = self->call();
- if (done)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- delete self;
- }
- }
- bool call()
- {
- return mCallable();
- }
-private:
- bool_func_t mCallable;
-};
-
-void doOnIdleRepeating(bool_func_t callable)
-{
- OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
-}
-
-class NullaryFuncEventTimer: public LLEventTimer
-{
-public:
- NullaryFuncEventTimer(nullary_func_t callable, F32 seconds):
- LLEventTimer(seconds),
- mCallable(callable)
- {
- }
-
-private:
- bool tick()
- {
- mCallable();
- return true;
- }
-
- nullary_func_t mCallable;
-};
-
-// Call a given callable once after specified interval.
-void doAfterInterval(nullary_func_t callable, F32 seconds)
-{
- new NullaryFuncEventTimer(callable, seconds);
-}
-
-class BoolFuncEventTimer: public LLEventTimer
-{
-public:
- BoolFuncEventTimer(bool_func_t callable, F32 seconds):
- LLEventTimer(seconds),
- mCallable(callable)
- {
- }
-private:
- bool tick()
- {
- return mCallable();
- }
-
- bool_func_t mCallable;
-};
-
-// Call a given callable every specified number of seconds, until it returns true.
-void doPeriodically(bool_func_t callable, F32 seconds)
-{
- new BoolFuncEventTimer(callable, seconds);
-}
-
-#ifdef _DEBUG
-
-void test1(void *data)
-{
- S32 *s32_data = (S32 *)data;
- LL_INFOS() << "testfunc1 " << *s32_data << LL_ENDL;
-}
-
-
-void test2(void *data)
-{
- S32 *s32_data = (S32 *)data;
- LL_INFOS() << "testfunc2 " << *s32_data << LL_ENDL;
-}
-
-
-void
-LLCallbackList::test()
-{
- S32 a = 1;
- S32 b = 2;
- LLCallbackList *list = new LLCallbackList;
-
- LL_INFOS() << "Testing LLCallbackList" << LL_ENDL;
-
- if (!list->deleteFunction(NULL))
- {
- LL_INFOS() << "passed 1" << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "error, removed function from empty list" << LL_ENDL;
- }
-
- // LL_INFOS() << "This should crash" << LL_ENDL;
- // list->addFunction(NULL);
-
- list->addFunction(&test1, &a);
- list->addFunction(&test1, &a);
-
- LL_INFOS() << "Expect: test1 1, test1 1" << LL_ENDL;
- list->callFunctions();
-
- list->addFunction(&test1, &b);
- list->addFunction(&test2, &b);
-
- LL_INFOS() << "Expect: test1 1, test1 1, test1 2, test2 2" << LL_ENDL;
- list->callFunctions();
-
- if (list->deleteFunction(&test1, &b))
- {
- LL_INFOS() << "passed 3" << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "error removing function" << LL_ENDL;
- }
-
- LL_INFOS() << "Expect: test1 1, test1 1, test2 2" << LL_ENDL;
- list->callFunctions();
-
- list->deleteAllFunctions();
-
- LL_INFOS() << "Expect nothing" << LL_ENDL;
- list->callFunctions();
-
- LL_INFOS() << "nothing :-)" << LL_ENDL;
-
- delete list;
-
- LL_INFOS() << "test complete" << LL_ENDL;
-}
-
-#endif // _DEBUG
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 305b5be194..b0240c62be 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -125,6 +125,7 @@ public:
mUserNameTextBox(NULL),
mTimeBoxTextBox(NULL),
mNeedsTimeBox(true),
+ mIsFromScript(false),
mAvatarNameCacheConnection()
{}
@@ -425,6 +426,7 @@ public:
time_t current_time = time_corrected();
time_t message_time = (time_t)(current_time - LLFrameTimer::getElapsedSeconds() + mTime);
+ // Report abuse shouldn't use AM/PM, use 24-hour time
time_string = "[" + LLTrans::getString("TimeMonth") + "]/["
+ LLTrans::getString("TimeDay") + "]/["
+ LLTrans::getString("TimeYear") + "] ["
@@ -658,11 +660,13 @@ public:
const LLUUID& getAvatarId () const { return mAvatarID;}
- void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args)
+ void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args, bool is_script)
{
mAvatarID = chat.mFromID;
mSessionID = chat.mSessionID;
mSourceType = chat.mSourceType;
+ mIsFromScript = is_script;
+ mPrefix = mIsFromScript ? LLTrans::getString("ScriptBy") : "";
// To be able to report a message, we need a copy of it's text
// and it's easier to store text directly than trying to get
@@ -732,7 +736,7 @@ public:
username_end == (chat.mFromName.length() - 1))
{
mFrom = chat.mFromName.substr(0, username_start);
- user_name->setValue(mFrom);
+ user_name->setValue(mPrefix + mFrom);
if (gSavedSettings.getBOOL("NameTagShowUsernames"))
{
@@ -774,7 +778,7 @@ public:
switch (mSourceType)
{
case CHAT_SOURCE_AGENT:
- icon->setValue(chat.mFromID);
+ icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(chat.mFromID));
break;
case CHAT_SOURCE_OBJECT:
icon->setValue(LLSD("OBJECT_Icon"));
@@ -787,7 +791,7 @@ public:
icon->setValue(LLSD("Command_Destinations_Icon"));
break;
case CHAT_SOURCE_UNKNOWN:
- icon->setValue(LLSD("Unknown_Icon"));
+ icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD("Unknown_Icon"));
}
// In case the message came from an object, save the object info
@@ -868,7 +872,7 @@ protected:
LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleObject.get();
if (!menu)
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable;
registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2));
registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2));
@@ -896,9 +900,9 @@ protected:
LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get();
if (!menu)
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable;
- registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2));
+ registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK);
registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2));
registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2));
registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2));
@@ -1029,7 +1033,7 @@ private:
mFrom = av_name.getDisplayName();
LLTextBox* user_name = getChild<LLTextBox>("user_name");
- user_name->setValue( LLSD(av_name.getDisplayName() ) );
+ user_name->setValue(LLSD(mPrefix + av_name.getDisplayName()));
user_name->setToolTip( av_name.getUserName() );
if (gSavedSettings.getBOOL("NameTagShowUsernames") &&
@@ -1071,6 +1075,9 @@ protected:
bool mNeedsTimeBox;
+ bool mIsFromScript;
+ std::string mPrefix;
+
private:
boost::signals2::connection mAvatarNameCacheConnection;
};
@@ -1088,6 +1095,7 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
mTopHeaderPad(p.top_header_pad),
mBottomHeaderPad(p.bottom_header_pad),
mIsLastMessageFromLog(false),
+ mIsLastFromScript(false),
mNotifyAboutUnreadMsg(p.notify_unread_msg)
{
LLTextEditor::Params editor_params(p);
@@ -1185,11 +1193,11 @@ LLView* LLChatHistory::getSeparator()
return separator;
}
-LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args)
+LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args, bool is_script)
{
LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
if (header)
- header->setup(chat, style_params, args);
+ header->setup(chat, style_params, args, is_script);
return header;
}
@@ -1263,8 +1271,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
name_params.color(name_color);
name_params.readonly_color(name_color);
- std::string prefix = chat.mText.substr(0, 4);
-
+ auto [message, is_lua] = LLStringUtil::withoutPrefix(chat.mText, LUA_PREFIX);
+ std::string prefix = message.substr(0, 4);
//IRC styled /me messages.
bool irc_me = prefix == "/me " || prefix == "/me'";
@@ -1340,6 +1348,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
// names showing
if (args["show_names_for_p2p_conv"].asBoolean() && utf8str_trim(chat.mFromName).size())
{
+ std::string script_prefix = is_lua ? LLTrans::getString("ScriptBy") : "";
// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
if (chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
{
@@ -1364,7 +1373,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID));
// Add link to avatar's inspector and delimiter to message.
- mEditor->appendText(std::string(link_params.link_href) + delimiter,
+ mEditor->appendText(script_prefix + std::string(link_params.link_href) + delimiter,
prependNewLineState, link_params);
prependNewLineState = false;
}
@@ -1377,7 +1386,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
}
else
{
- mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>" + delimiter,
+ mEditor->appendText(script_prefix + "<nolink>" + chat.mFromName + "</nolink>" + delimiter,
prependNewLineState, body_message_params);
prependNewLineState = false;
}
@@ -1398,7 +1407,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
&& mLastFromID == chat.mFromID
&& mLastMessageTime.notNull()
&& (new_message_time.secondsSinceEpoch() - mLastMessageTime.secondsSinceEpoch()) < 60.0
- && mIsLastMessageFromLog == message_from_log) //distinguish between current and previous chat session's histories
+ && mIsLastMessageFromLog == message_from_log //distinguish between current and previous chat session's histories
+ && mIsLastFromScript == is_lua)
{
view = getSeparator();
if (!view)
@@ -1413,7 +1423,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
}
else
{
- view = getHeader(chat, name_params, args);
+ view = getHeader(chat, name_params, args, is_lua);
if (!view)
{
LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL;
@@ -1442,6 +1452,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
mLastFromID = chat.mFromID;
mLastMessageTime = new_message_time;
mIsLastMessageFromLog = message_from_log;
+ mIsLastFromScript = is_lua;
}
// body of the message processing
@@ -1496,7 +1507,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
// usual messages showing
else if (!teleport_separator)
{
- std::string message = irc_me ? chat.mText.substr(3) : chat.mText;
+ message = irc_me ? message.substr(3) : message;
//MESSAGE TEXT PROCESSING
//*HACK getting rid of redundant sender names in system notifications sent using sender name (see EXT-5010)
diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h
index b8364ff860..8acbea6ed5 100644
--- a/indra/newview/llchathistory.h
+++ b/indra/newview/llchathistory.h
@@ -101,7 +101,7 @@ class LLChatHistory : public LLUICtrl
* Builds a message header.
* @return pointer to LLView header object.
*/
- LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args);
+ LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args, bool is_script = false);
public:
~LLChatHistory();
LLSD getValue() const;
@@ -127,6 +127,7 @@ class LLChatHistory : public LLUICtrl
LLDate mLastMessageTime;
bool mIsLastMessageFromLog;
bool mNotifyAboutUnreadMsg;
+ bool mIsLastFromScript;
//std::string mLastMessageTimeStr;
std::string mMessageHeaderFilename;
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index 550dfeb802..f1ed55e647 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -188,6 +188,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)
int sType = notification["source"].asInteger();
mSourceType = (EChatSourceType)sType;
+ mIsFromScript = notification["is_lua"].asBoolean();
std::string color_name = notification["text_color"].asString();
@@ -215,7 +216,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)
{
std::string str_sender;
- str_sender = fromName;
+ str_sender = mIsFromScript ? LLTrans::getString("ScriptBy") + fromName : fromName;
str_sender+=" ";
@@ -397,7 +398,7 @@ void LLFloaterIMNearbyChatToastPanel::draw()
else if(mSourceType == CHAT_SOURCE_SYSTEM)
icon->setValue(LLSD("SL_Logo"));
else if(mSourceType == CHAT_SOURCE_AGENT)
- icon->setValue(mFromID);
+ icon->setValue(mIsFromScript ? LLSD("Inv_Script") : LLSD(mFromID));
else if(!mFromID.isNull())
icon->setValue(mFromID);
}
diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h
index 4ae73a0c43..54b757d217 100644
--- a/indra/newview/llchatitemscontainerctrl.h
+++ b/indra/newview/llchatitemscontainerctrl.h
@@ -48,7 +48,8 @@ protected:
LLFloaterIMNearbyChatToastPanel()
:
mIsDirty(false),
- mSourceType(CHAT_SOURCE_OBJECT)
+ mSourceType(CHAT_SOURCE_OBJECT),
+ mIsFromScript(false)
{};
public:
~LLFloaterIMNearbyChatToastPanel(){}
@@ -58,6 +59,8 @@ public:
const LLUUID& getFromID() const { return mFromID;}
const std::string& getFromName() const { return mFromName; }
+ bool isFromScript() { return mIsFromScript; }
+
//void addText (const std::string& message , const LLStyle::Params& input_params = LLStyle::Params());
//void setMessage (const LLChat& msg);
void snapToMessageHeight ();
@@ -88,6 +91,7 @@ private:
std::string mFromName;
EChatSourceType mSourceType;
LLChatMsgBox* mMsgText;
+ bool mIsFromScript;
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 4c0f160f6f..ec2b570ccd 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -210,9 +210,9 @@ void LLNotificationChiclet::createMenu()
return;
}
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
registrar.add("NotificationWellChicletMenu.Action",
- boost::bind(&LLNotificationChiclet::onMenuItemClicked, this, _2));
+ boost::bind(&LLNotificationChiclet::onMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK);
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
enable_registrar.add("NotificationWellChicletMenu.EnableItem",
@@ -1132,8 +1132,8 @@ void LLScriptChiclet::createPopupMenu()
if(!canCreateMenu())
return;
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
- registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2));
+ ScopedRegistrarHelper registrar;
+ registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK);
LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
("menu_script_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
@@ -1215,8 +1215,8 @@ void LLInvOfferChiclet::createPopupMenu()
if(!canCreateMenu())
return;
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
- registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2));
+ ScopedRegistrarHelper registrar;
+ registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK);
LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>
("menu_inv_offer_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp
index 47803edc73..b9df091f54 100644
--- a/indra/newview/llcofwearables.cpp
+++ b/indra/newview/llcofwearables.cpp
@@ -138,7 +138,7 @@ protected:
/*virtual*/ LLContextMenu* createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
registrar.add("Attachment.Touch", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs));
registrar.add("Attachment.Edit", boost::bind(handleMultiple, handle_item_edit, mUUIDs));
@@ -191,7 +191,7 @@ protected:
/*virtual*/ LLContextMenu* createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
LLUUID selected_id = mUUIDs.back();
@@ -251,9 +251,9 @@ protected:
LLUUID selected_id = mUUIDs.back();
LLPanelOutfitEdit* panel_oe = dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit"));
- registrar.add("BodyPart.Replace", boost::bind(&LLPanelOutfitEdit::onReplaceMenuItemClicked, panel_oe, selected_id));
- registrar.add("BodyPart.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
- registrar.add("BodyPart.Create", boost::bind(&CofBodyPartContextMenu::createNew, this, selected_id));
+ registrar.add("BodyPart.Replace", { boost::bind(&LLPanelOutfitEdit::onReplaceMenuItemClicked, panel_oe, selected_id) });
+ registrar.add("BodyPart.Edit", { boost::bind(LLAgentWearables::editWearable, selected_id) });
+ registrar.add("BodyPart.Create", { boost::bind(&CofBodyPartContextMenu::createNew, this, selected_id) });
enable_registrar.add("BodyPart.OnEnable", boost::bind(&CofBodyPartContextMenu::onEnable, this, _2));
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
index 9201241856..660fb1b41a 100644
--- a/indra/newview/llcontrolavatar.cpp
+++ b/indra/newview/llcontrolavatar.cpp
@@ -129,14 +129,14 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
{
LLVector3 pos_box_offset = point_to_box_offset(vol_pos, unshift_extents);
F32 offset_dist = pos_box_offset.length();
- if (offset_dist > MAX_LEGAL_OFFSET && offset_dist > 0.f)
+ if (offset_dist > max_legal_offset && offset_dist > 0.f)
{
- F32 target_dist = (offset_dist - MAX_LEGAL_OFFSET);
+ F32 target_dist = (offset_dist - max_legal_offset);
new_pos_fixup = (target_dist/offset_dist)*pos_box_offset;
}
if (new_pos_fixup != mPositionConstraintFixup)
{
- LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup "
+ LL_DEBUGS("ConstraintFix") << getDebugName() << " pos fix, offset_dist " << offset_dist << " pos fixup "
<< new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL;
LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL;
LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL;
@@ -144,11 +144,11 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
}
}
- if (box_size/mScaleConstraintFixup > MAX_LEGAL_SIZE)
+ if (box_size/mScaleConstraintFixup > max_legal_size)
{
- new_scale_fixup = mScaleConstraintFixup* MAX_LEGAL_SIZE /box_size;
- LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup "
- << mScaleConstraintFixup << " max legal " << MAX_LEGAL_SIZE
+ new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size;
+ LL_DEBUGS("ConstraintFix") << getDebugName() << " scale fix, box_size " << box_size << " fixup "
+ << mScaleConstraintFixup << " max legal " << max_legal_size
<< " -> new scale " << new_scale_fixup << LL_ENDL;
}
}
@@ -231,7 +231,7 @@ void LLControlAvatar::matchVolumeTransform()
const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo();
if (skin_info)
{
- LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL;
+ LL_DEBUGS("BindShape") << getDebugName() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL;
bind_rot = LLSkinningUtil::getUnscaledQuaternion(LLMatrix4(skin_info->mBindShapeMatrix));
}
#endif
diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp
index ed563cbec9..ed16a4b135 100644
--- a/indra/newview/llconversationlog.cpp
+++ b/indra/newview/llconversationlog.cpp
@@ -118,11 +118,21 @@ const std::string LLConversation::createTimestamp(const U64Seconds& utc_time)
LLSD substitution;
substitution["datetime"] = (S32)utc_time.value();
- timeStr = "["+LLTrans::getString ("TimeMonth")+"]/["
- +LLTrans::getString ("TimeDay")+"]/["
- +LLTrans::getString ("TimeYear")+"] ["
- +LLTrans::getString ("TimeHour")+"]:["
- +LLTrans::getString ("TimeMin")+"]";
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ timeStr = "[" + LLTrans::getString("TimeMonth") + "]/["
+ + LLTrans::getString("TimeDay") + "]/["
+ + LLTrans::getString("TimeYear") + "] [";
+ if (use_24h)
+ {
+ timeStr += LLTrans::getString("TimeHour") + "]:["
+ + LLTrans::getString("TimeMin") + "]";
+ }
+ else
+ {
+ timeStr += LLTrans::getString("TimeHour12") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeAMPM") + "]";
+ }
LLStringUtil::format (timeStr, substitution);
diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp
index 65863f0a5e..8376f5463c 100644
--- a/indra/newview/llconversationloglist.cpp
+++ b/indra/newview/llconversationloglist.cpp
@@ -47,11 +47,11 @@ LLConversationLogList::LLConversationLogList(const Params& p)
LLConversationLog::instance().addObserver(this);
// Set up context menu.
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar check_registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
- registrar.add ("Calllog.Action", boost::bind(&LLConversationLogList::onCustomAction, this, _2));
+ registrar.add ("Calllog.Action", boost::bind(&LLConversationLogList::onCustomAction, this, _2), cb_info::UNTRUSTED_BLOCK);
check_registrar.add ("Calllog.Check", boost::bind(&LLConversationLogList::isActionChecked,this, _2));
enable_registrar.add("Calllog.Enable", boost::bind(&LLConversationLogList::isActionEnabled,this, _2));
@@ -95,6 +95,7 @@ bool LLConversationLogList::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
context_menu->buildDrawLabels();
context_menu->updateParent(LLMenuGL::sMenuContainer);
+
LLMenuGL::showPopup(this, context_menu, x, y);
}
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index c1e48c63a9..d5486b9f4a 100644
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -79,6 +79,9 @@ public:
virtual LLPointer<LLUIImage> getOpenIcon() const { return getIcon(); }
virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; }
virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
+ virtual bool isFavorite() const { return false; }
+ virtual bool isAgentInventory() const { return false; }
+ virtual bool isAgentInventoryRoot() const { return false; }
virtual bool isItemRenameable() const { return true; }
virtual bool renameItem(const std::string& new_name) { mName = new_name; mNeedsRefresh = true; return true; }
virtual bool isItemMovable( void ) const { return false; }
diff --git a/indra/newview/llcylinder.cpp b/indra/newview/llcylinder.cpp
index c347d3e1be..d5f1e25151 100644
--- a/indra/newview/llcylinder.cpp
+++ b/indra/newview/llcylinder.cpp
@@ -29,7 +29,7 @@
#include "llcylinder.h"
#include "llerror.h"
-#include "math.h"
+#include <cmath>
#include "llmath.h"
#include "noise.h"
#include "v3math.h"
diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp
index 1425aab947..bc00f4179e 100644
--- a/indra/newview/lldirpicker.cpp
+++ b/indra/newview/lldirpicker.cpp
@@ -41,11 +41,6 @@
# include "llfilepicker.h"
#endif
-#ifdef LL_FLTK
- #include "FL/Fl.H"
- #include "FL/Fl_Native_File_Chooser.H"
-#endif
-
#if LL_WINDOWS
#include <shlobj.h>
#endif
@@ -219,28 +214,20 @@ LLDirPicker::LLDirPicker() :
mFileName(NULL),
mLocked(false)
{
-#ifndef LL_FLTK
mFilePicker = new LLFilePicker();
-#endif
reset();
}
LLDirPicker::~LLDirPicker()
{
-#ifndef LL_FLTK
delete mFilePicker;
-#endif
}
void LLDirPicker::reset()
{
-#ifndef LL_FLTK
if (mFilePicker)
mFilePicker->reset();
-#else
- mDir = "";
-#endif
}
bool LLDirPicker::getDir(std::string* filename, bool blocking)
@@ -253,38 +240,16 @@ bool LLDirPicker::getDir(std::string* filename, bool blocking)
return false;
}
-#ifdef LL_FLTK
- gViewerWindow->getWindow()->beforeDialog();
- Fl_Native_File_Chooser flDlg;
- flDlg.title(LLTrans::getString("choose_the_directory").c_str());
- flDlg.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY );
- int res = flDlg.show();
- gViewerWindow->getWindow()->afterDialog();
- if( res == 0 )
- {
- char const *pDir = flDlg.filename(0);
- if( pDir )
- mDir = pDir;
- }
- else if( res == -1 )
- {
- LL_WARNS() << "FLTK failed: " << flDlg.errmsg() << LL_ENDL;
- }
- return !mDir.empty();
-#endif
+ return false;
}
std::string LLDirPicker::getDirName()
{
-#ifndef LL_FLTK
if (mFilePicker)
{
return mFilePicker->getFirstFile();
}
return "";
-#else
- return mDir;
-#endif
}
#else // not implemented
diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h
index 4bbe7db144..2d5bfc3a75 100644
--- a/indra/newview/lldirpicker.h
+++ b/indra/newview/lldirpicker.h
@@ -77,10 +77,8 @@ private:
#if LL_LINUX || LL_DARWIN || __FreeBSD__
// On Linux we just implement LLDirPicker on top of LLFilePicker
-#ifndef LL_FLTK
LLFilePicker *mFilePicker;
#endif
-#endif
std::string* mFileName;
diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h
index 6683646a9b..0dc2515e02 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.h
+++ b/indra/newview/lldonotdisturbnotificationstorage.h
@@ -42,7 +42,7 @@ public:
~LLDoNotDisturbNotificationStorageTimer();
public:
- bool tick();
+ bool tick() override;
};
class LLDoNotDisturbNotificationStorage : public LLParamSingleton<LLDoNotDisturbNotificationStorage>, public LLNotificationStorage
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 87b6ce6cb3..5379bcc985 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -732,15 +732,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
{// If we need shaders, and we're not ALREADY using the proper shader, then bind it
// (this way we won't rebind shaders unnecessarily).
gPipeline.bindDeferredShaderFast(*target_shader);
-
- if (params.mFullbright)
- { // make sure the bind the exposure map for fullbright shaders so they can cancel out exposure
- S32 channel = target_shader->enableTexture(LLShaderMgr::EXPOSURE_MAP);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap);
- }
- }
}
LLVector4 spec_color(1, 1, 1, 1);
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index bf593bff07..754fcd4c17 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -300,13 +300,6 @@ void LLDrawPoolBump::beginFullbrightShiny()
shader = shader->mRiggedVariant;
}
- // bind exposure map so fullbright shader can cancel out exposure
- S32 channel = shader->enableTexture(LLShaderMgr::EXPOSURE_MAP);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap);
- }
-
LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
if (cube_map && !LLPipeline::sReflectionProbesEnabled)
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 2f4f47df6f..60e40d3dba 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -296,7 +296,7 @@ void LLDrawPoolTerrain::renderFullShaderTextures()
// GL_BLEND disabled by default
drawLoop();
- // Disable multitexture
+ // Disable textures
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0);
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL1);
@@ -557,7 +557,7 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool use_local_materials)
// GL_BLEND disabled by default
drawLoop();
- // Disable multitexture
+ // Disable textures
if (paint_type == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE)
{
@@ -777,7 +777,7 @@ void LLDrawPoolTerrain::renderFull4TU()
}
LLVertexBuffer::unbind();
- // Disable multitexture
+ // Disable textures
gGL.getTexUnit(3)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(3)->disable();
gGL.getTexUnit(3)->activate();
@@ -971,7 +971,7 @@ void LLDrawPoolTerrain::renderFull2TU()
// Restore blend state
gGL.setSceneBlendType(LLRender::BT_ALPHA);
- // Disable multitexture
+ // Disable textures
gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(1)->disable();
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 305215f541..e6d0b036e0 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -32,7 +32,6 @@
#include "llface.h"
#include "llimage.h"
#include "llrender.h"
-#include "llatmosphere.h"
#include "llenvironment.h"
#include "llglslshader.h"
#include "llgl.h"
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 05bd704556..a125dcb7aa 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -54,7 +54,6 @@
#include "llregioninfomodel.h"
-#include "llatmosphere.h"
#include "llagent.h"
#include "roles_constants.h"
#include "llestateinfomodel.h"
@@ -965,54 +964,6 @@ LLSettingsWater::ptr_t LLEnvironment::getCurrentWater() const
return pwater;
}
-void LayerConfigToDensityLayer(const LLSD& layerConfig, DensityLayer& layerOut)
-{
- layerOut.constant_term = (F32)layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM].asReal();
- layerOut.exp_scale = (F32)layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR].asReal();
- layerOut.exp_term = (F32)layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal();
- layerOut.linear_term = (F32)layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM].asReal();
- layerOut.width = (F32)layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH].asReal();
-}
-
-void LLEnvironment::getAtmosphericModelSettings(AtmosphericModelSettings& settingsOut, const LLSettingsSky::ptr_t &psky)
-{
- settingsOut.m_skyBottomRadius = psky->getSkyBottomRadius();
- settingsOut.m_skyTopRadius = psky->getSkyTopRadius();
- settingsOut.m_sunArcRadians = psky->getSunArcRadians();
- settingsOut.m_mieAnisotropy = psky->getMieAnisotropy();
-
- LLSD rayleigh = psky->getRayleighConfigs();
- settingsOut.m_rayleighProfile.clear();
- for (LLSD::array_iterator itf = rayleigh.beginArray(); itf != rayleigh.endArray(); ++itf)
- {
- DensityLayer layer;
- LLSD& layerConfig = (*itf);
- LayerConfigToDensityLayer(layerConfig, layer);
- settingsOut.m_rayleighProfile.push_back(layer);
- }
-
- LLSD mie = psky->getMieConfigs();
- settingsOut.m_mieProfile.clear();
- for (LLSD::array_iterator itf = mie.beginArray(); itf != mie.endArray(); ++itf)
- {
- DensityLayer layer;
- LLSD& layerConfig = (*itf);
- LayerConfigToDensityLayer(layerConfig, layer);
- settingsOut.m_mieProfile.push_back(layer);
- }
- settingsOut.m_mieAnisotropy = psky->getMieAnisotropy();
-
- LLSD absorption = psky->getAbsorptionConfigs();
- settingsOut.m_absorptionProfile.clear();
- for (LLSD::array_iterator itf = absorption.beginArray(); itf != absorption.endArray(); ++itf)
- {
- DensityLayer layer;
- LLSD& layerConfig = (*itf);
- LayerConfigToDensityLayer(layerConfig, layer);
- settingsOut.m_absorptionProfile.push_back(layer);
- }
-}
-
bool LLEnvironment::canAgentUpdateParcelEnvironment() const
{
LLParcel *parcel(LLViewerParcelMgr::instance().getAgentOrSelectedParcel());
@@ -2744,13 +2695,6 @@ bool LLEnvironment::DayInstance::setSky(const LLSettingsSky::ptr_t &psky)
mSky->update();
mBlenderSky.reset();
- if (gAtmosphere)
- {
- AtmosphericModelSettings settings;
- LLEnvironment::getAtmosphericModelSettings(settings, psky);
- gAtmosphere->configureAtmosphericModel(settings);
- }
-
return changed;
}
diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h
index e56548d618..559a34bc47 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -38,8 +38,6 @@
#include "llsettingswater.h"
#include "llsettingsdaycycle.h"
-#include "llatmosphere.h"
-
#include "llglslshader.h"
#include <boost/signals2.hpp>
@@ -133,8 +131,6 @@ public:
LLSettingsSky::ptr_t getCurrentSky() const;
LLSettingsWater::ptr_t getCurrentWater() const;
- static void getAtmosphericModelSettings(AtmosphericModelSettings& settingsOut, const LLSettingsSky::ptr_t &psky);
-
void update(const LLViewerCamera * cam);
static void updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting);
diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp
index 5c46eb9d80..093f978e74 100644
--- a/indra/newview/llexpandabletextbox.cpp
+++ b/indra/newview/llexpandabletextbox.cpp
@@ -42,17 +42,18 @@ public:
mEditor(editor),
mStyle(style),
mExpanderLabel(utf8str_to_wstring(more_text))
- {}
+ {
+ }
/*virtual*/ LLTextSegmentPtr clone(LLTextBase& target) const
{
- LLStyleSP sp(cloneStyle(target, mStyle));
+ LLStyleSP sp((&target == &mEditor) ? mStyle : mStyle->clone());
LLExpanderSegment* copy = new LLExpanderSegment(sp, mStart, mEnd, LLStringUtil::null, target);
copy->mExpanderLabel = mExpanderLabel;
return copy;
}
- /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
+ /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
{
// more label always spans width of text box
if (num_chars == 0)
@@ -67,11 +68,13 @@ public:
}
return true;
}
- /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const
+
+ /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const
{
return start_offset;
}
- /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const
+
+ /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const
{
// require full line to ourselves
if (line_offset == 0)
@@ -85,7 +88,8 @@ public:
return 0;
}
}
- /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect)
+
+ /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect)
{
F32 right_x;
mStyle->getFont()->render(mExpanderLabel, start,
@@ -99,6 +103,7 @@ public:
mEditor.getUseEllipses(), mEditor.getUseColor());
return right_x;
}
+
/*virtual*/ bool canEdit() const { return false; }
// eat handleMouseDown event so we get the mouseup event
/*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) { return true; }
@@ -108,6 +113,7 @@ public:
LLUI::getInstance()->getWindow()->setCursor(UI_CURSOR_HAND);
return true;
}
+
private:
LLTextBase& mEditor;
LLStyleSP mStyle;
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 377710c170..49fd6a29a2 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -430,7 +430,7 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
{
// Register callback for menus with current registrar (will be parent panel's registrar)
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
- boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2));
+ { boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2), cb_info::UNTRUSTED_BLOCK });
// Add this if we need to selectively enable items
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected",
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 88024b8390..16007b623d 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -377,33 +377,6 @@ bool LLFeatureManager::parseFeatureTable(std::string filename)
F32 gpu_benchmark();
-#if LL_WINDOWS
-
-F32 logExceptionBenchmark()
-{
- // FIXME: gpu_benchmark uses many C++ classes on the stack to control state.
- // SEH exceptions with our current exception handling options do not call
- // destructors for these classes, resulting in an undefined state should
- // this handler be invoked.
- F32 gbps = -1;
- __try
- {
- gbps = gpu_benchmark();
- }
- __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation()))
- {
- // HACK - ensure that profiling is disabled
- LLGLSLShader::finishProfile();
-
- // convert to C++ styled exception
- char integer_string[32];
- sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
- throw std::exception(integer_string);
- }
- return gbps;
-}
-#endif
-
bool LLFeatureManager::loadGPUClass()
{
if (!gSavedSettings.getBOOL("SkipBenchmark"))
@@ -421,6 +394,8 @@ bool LLFeatureManager::loadGPUClass()
}
catch (const std::exception& e)
{
+ // HACK - ensure that profiling is disabled
+ LLGLSLShader::finishProfile();
gbps = -1.f;
LL_WARNS("RenderInit") << "GPU benchmark failed: " << e.what() << LL_ENDL;
}
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 2516bece8d..9e2bcc5148 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -36,16 +36,8 @@
#include "llviewercontrol.h"
#include "llwindow.h" // beforeDialog()
-#if LL_SDL
-#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers
-#endif // LL_SDL
-
-#ifdef LL_FLTK
- #include "FL/Fl.H"
- #include "FL/Fl_Native_File_Chooser.H"
-#endif
-
#if LL_LINUX || __FreeBSD__
+#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers
#include "llhttpconstants.h" // file picker uses some of thes constants on Linux
#endif
@@ -70,6 +62,7 @@ LLFilePicker LLFilePicker::sInstance;
#define MATERIAL_TEXTURES_FILTER L"GLTF Import (*.gltf; *.glb; *.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.gltf;*.glb;*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
#define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0"
#define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0"
+#define LUA_FILTER L"Script files (*.lua)\0*.lua\0"
#endif
#ifdef LL_DARWIN
@@ -246,6 +239,10 @@ bool LLFilePicker::setupFilter(ELoadFilter filter)
mOFN.lpstrFilter = DICTIONARY_FILTER \
L"\0";
break;
+ case FFLOAD_LUA:
+ mOFN.lpstrFilter = LUA_FILTER \
+ L"\0";
+ break;
default:
res = false;
break;
@@ -675,7 +672,6 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF
break;
case FFLOAD_HDRI:
allowedv->push_back("exr");
- case FFLOAD_MODEL:
case FFLOAD_COLLADA:
allowedv->push_back("dae");
break;
@@ -1108,231 +1104,488 @@ bool LLFilePicker::getSaveFileModeless(ESaveFilter filter,
#elif LL_LINUX || __FreeBSD__
-#if LL_FLTK
+# if LL_GTK
-bool LLFilePicker::getSaveFileModeless(ESaveFilter filter,
- const std::string& filename,
- void (*callback)(bool, std::string&, void*),
- void *userdata)
+// static
+void LLFilePicker::add_to_selectedfiles(gpointer data, gpointer user_data)
{
- LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL;
- return FALSE;
+ // We need to run g_filename_to_utf8 in the user's locale
+ std::string saved_locale(setlocale(LC_ALL, NULL));
+ setlocale(LC_ALL, "");
+
+ LLFilePicker* picker = (LLFilePicker*) user_data;
+ GError *error = NULL;
+ gchar* filename_utf8 = g_filename_to_utf8((gchar*)data,
+ -1, NULL, NULL, &error);
+ if (error)
+ {
+ // *FIXME.
+ // This condition should really be notified to the user, e.g.
+ // through a message box. Just logging it is inappropriate.
+
+ // g_filename_display_name is ideal, but >= glib 2.6, so:
+ // a hand-rolled hacky makeASCII which disallows control chars
+ std::string display_name;
+ for (const gchar *str = (const gchar *)data; *str; str++)
+ {
+ display_name += (char)((*str >= 0x20 && *str <= 0x7E) ? *str : '?');
+ }
+ LL_WARNS() << "g_filename_to_utf8 failed on \"" << display_name << "\": " << error->message << LL_ENDL;
+ }
+
+ if (filename_utf8)
+ {
+ picker->mFiles.push_back(std::string(filename_utf8));
+ LL_DEBUGS() << "ADDED FILE " << filename_utf8 << LL_ENDL;
+ g_free(filename_utf8);
+ }
+
+ setlocale(LC_ALL, saved_locale.c_str());
}
-bool LLFilePicker::getOpenFileModeless(ELoadFilter filter,
- void (*callback)(bool, std::vector<std::string> &, void*),
- void *userdata)
+// static
+void LLFilePicker::chooser_responder(GtkWidget *widget, gint response, gpointer user_data)
{
- LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL;
- return FALSE;
+ LLFilePicker* picker = (LLFilePicker*)user_data;
+
+ LL_DEBUGS() << "GTK DIALOG RESPONSE " << response << LL_ENDL;
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ GSList *file_list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
+ g_slist_foreach(file_list, (GFunc)add_to_selectedfiles, user_data);
+ g_slist_foreach(file_list, (GFunc)g_free, NULL);
+ g_slist_free (file_list);
+ }
+
+ // let's save the extension of the last added file(considering current filter)
+ GtkFileFilter *gfilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widget));
+ if(gfilter)
+ {
+ std::string filter = gtk_file_filter_get_name(gfilter);
+
+ if(filter == LLTrans::getString("png_image_files"))
+ {
+ picker->mCurrentExtension = ".png";
+ }
+ else if(filter == LLTrans::getString("targa_image_files"))
+ {
+ picker->mCurrentExtension = ".tga";
+ }
+ }
+
+ // set the default path for this usage context.
+ const char* cur_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(widget));
+ if (cur_folder != NULL)
+ {
+ picker->mContextToPathMap[picker->mCurContextName] = cur_folder;
+ }
+
+ gtk_widget_destroy(widget);
+ gtk_main_quit();
}
-bool LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter,
- void (*callback)(bool, std::vector<std::string> &, void*),
- void *userdata )
+
+GtkWindow* LLFilePicker::buildFilePicker(bool is_save, bool is_folder, std::string context)
{
- LL_ERRS() << "NOT IMPLEMENTED" << LL_ENDL;
- return FALSE;
+#ifndef LL_MESA_HEADLESS
+ if (LLWindowSDL::ll_try_gtk_init())
+ {
+ GtkWidget *win = NULL;
+ GtkFileChooserAction pickertype =
+ is_save?
+ (is_folder?
+ GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER :
+ GTK_FILE_CHOOSER_ACTION_SAVE) :
+ (is_folder?
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
+ GTK_FILE_CHOOSER_ACTION_OPEN);
+
+ win = gtk_file_chooser_dialog_new(NULL, NULL,
+ pickertype,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ is_folder ?
+ GTK_STOCK_APPLY :
+ (is_save ?
+ GTK_STOCK_SAVE :
+ GTK_STOCK_OPEN),
+ GTK_RESPONSE_ACCEPT,
+ (gchar *)NULL);
+ mCurContextName = context;
+
+ // get the default path for this usage context if it's been
+ // seen before.
+ std::map<std::string,std::string>::iterator
+ this_path = mContextToPathMap.find(context);
+ if (this_path != mContextToPathMap.end())
+ {
+ gtk_file_chooser_set_current_folder
+ (GTK_FILE_CHOOSER(win),
+ this_path->second.c_str());
+ }
+
+# if LL_X11
+ // Make GTK tell the window manager to associate this
+ // dialog with our non-GTK raw X11 window, which should try
+ // to keep it on top etc.
+ Window XWindowID = LLWindowSDL::get_SDL_XWindowID();
+ if (None != XWindowID)
+ {
+ gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin
+ GdkWindow *gdkwin = gdk_window_foreign_new(XWindowID);
+ gdk_window_set_transient_for(GTK_WIDGET(win)->window,
+ gdkwin);
+ }
+ else
+ {
+ LL_WARNS() << "Hmm, couldn't get xwid to use for transient." << LL_ENDL;
+ }
+# endif //LL_X11
+
+ g_signal_connect (GTK_FILE_CHOOSER(win),
+ "response",
+ G_CALLBACK(LLFilePicker::chooser_responder),
+ this);
+
+ gtk_window_set_modal(GTK_WINDOW(win), TRUE);
+
+ /* GTK 2.6: if (is_folder)
+ gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(win),
+ TRUE); */
+
+ return GTK_WINDOW(win);
+ }
+ else
+ {
+ return NULL;
+ }
+#else
+ return NULL;
+#endif //LL_MESA_HEADLESS
}
+static void add_common_filters_to_gtkchooser(GtkFileFilter *gfilter,
+ GtkWindow *picker,
+ std::string filtername)
+{
+ gtk_file_filter_set_name(gfilter, filtername.c_str());
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
+ gfilter);
+ GtkFileFilter *allfilter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(allfilter, "*");
+ gtk_file_filter_set_name(allfilter, LLTrans::getString("all_files").c_str());
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker), allfilter);
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(picker), gfilter);
+}
+static std::string add_simple_pattern_filter_to_gtkchooser(GtkWindow *picker,
+ std::string pattern,
+ std::string filtername)
+{
+ GtkFileFilter *gfilter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(gfilter, pattern.c_str());
+ add_common_filters_to_gtkchooser(gfilter, picker, filtername);
+ return filtername;
+}
-bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking )
+static std::string add_simple_mime_filter_to_gtkchooser(GtkWindow *picker,
+ std::string mime,
+ std::string filtername)
{
- return openFileDialog( filter, blocking, eSaveFile );
+ GtkFileFilter *gfilter = gtk_file_filter_new();
+ gtk_file_filter_add_mime_type(gfilter, mime.c_str());
+ add_common_filters_to_gtkchooser(gfilter, picker, filtername);
+ return filtername;
}
-bool LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
+static std::string add_wav_filter_to_gtkchooser(GtkWindow *picker)
{
- return openFileDialog( filter, blocking, eOpenFile );
+ return add_simple_mime_filter_to_gtkchooser(picker, "audio/x-wav",
+ LLTrans::getString("sound_files") + " (*.wav)");
}
-bool LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking)
+static std::string add_anim_filter_to_gtkchooser(GtkWindow *picker)
+{
+ GtkFileFilter *gfilter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(gfilter, "*.bvh");
+ gtk_file_filter_add_pattern(gfilter, "*.anim");
+ std::string filtername = LLTrans::getString("animation_files") + " (*.bvh; *.anim)";
+ add_common_filters_to_gtkchooser(gfilter, picker, filtername);
+ return filtername;
+}
+
+static std::string add_xml_filter_to_gtkchooser(GtkWindow *picker)
+{
+ return add_simple_pattern_filter_to_gtkchooser(picker, "*.xml",
+ LLTrans::getString("xml_files") + " (*.xml)");
+}
+
+static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker)
+{
+ return add_simple_pattern_filter_to_gtkchooser(picker, "*.dae",
+ LLTrans::getString("scene_files") + " (*.dae)");
+}
+
+static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
+{
+ GtkFileFilter *gfilter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(gfilter, "*.tga");
+ gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str());
+ gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str());
+ gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str());
+ std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)";
+ add_common_filters_to_gtkchooser(gfilter, picker, filtername);
+ return filtername;
+}
+
+static std::string add_script_filter_to_gtkchooser(GtkWindow *picker)
+{
+ return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN,
+ LLTrans::getString("script_files") + " (*.lsl)");
+}
+
+static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker)
+{
+ return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN,
+ LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)");
+}
+
+static std::string add_save_texture_filter_to_gtkchooser(GtkWindow *picker)
{
- return openFileDialog( filter, blocking, eOpenMultiple );
+ GtkFileFilter *gfilter_tga = gtk_file_filter_new();
+ GtkFileFilter *gfilter_png = gtk_file_filter_new();
+
+ gtk_file_filter_add_pattern(gfilter_tga, "*.tga");
+ gtk_file_filter_add_mime_type(gfilter_png, "image/png");
+ std::string caption = LLTrans::getString("save_texture_image_files") + " (*.tga; *.png)";
+ gtk_file_filter_set_name(gfilter_tga, LLTrans::getString("targa_image_files").c_str());
+ gtk_file_filter_set_name(gfilter_png, LLTrans::getString("png_image_files").c_str());
+
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
+ gfilter_png);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(picker),
+ gfilter_tga);
+ return caption;
}
-bool LLFilePicker::openFileDialog( int32_t filter, bool blocking, EType aType )
+bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking )
{
- if ( check_local_file_access_enabled() == false )
+ bool rtn = false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if (!check_local_file_access_enabled())
+ {
return false;
+ }
+
gViewerWindow->getWindow()->beforeDialog();
+
reset();
- Fl_Native_File_Chooser::Type flType = Fl_Native_File_Chooser::BROWSE_FILE;
- if( aType == eOpenMultiple )
- flType = Fl_Native_File_Chooser::BROWSE_MULTI_FILE;
- else if( aType == eSaveFile )
- flType = Fl_Native_File_Chooser::BROWSE_SAVE_FILE;
- Fl_Native_File_Chooser flDlg;
- std::string file_dialog_title;
- std::string file_dialog_filter;
- if (aType == EType::eSaveFile)
- {
- std::string file_type("all_files");
- switch ((ESaveFilter) filter)
+
+ GtkWindow* picker = buildFilePicker(true, false, "savefile");
+
+ if (picker)
+ {
+ std::string suggest_name = "untitled";
+ std::string suggest_ext = "";
+ std::string caption = LLTrans::getString("save_file_verb") + " ";
+ switch (filter)
{
- case FFSAVE_ALL:
- break;
- case FFSAVE_TGA:
- file_type = "targa_image_files";
- file_dialog_filter = "*.tga";
- break;
- case FFSAVE_BMP:
- file_type = "bitmap_image_files";
- file_dialog_filter = "*.bmp";
- break;
- case FFSAVE_AVI:
- file_type = "avi_movie_file";
- file_dialog_filter = "*.avi";
- break;
- case FFSAVE_ANIM:
- file_type = "xaf_animation_file";
- file_dialog_filter = "*.xaf";
- break;
- case FFSAVE_XML:
- file_type = "xml_file";
- file_dialog_filter = "*.xml";
- break;
- case FFSAVE_COLLADA:
- file_type = "collada_files";
- file_dialog_filter = "*.dae";
- break;
- case FFSAVE_RAW:
- file_type = "raw_file";
- file_dialog_filter = "*.raw";
- break;
- case FFSAVE_J2C:
- file_type = "compressed_image_files";
- file_dialog_filter = "*.j2c";
- break;
- case FFSAVE_PNG:
- file_type = "png_image_files";
- file_dialog_filter = "*.png";
- break;
- case FFSAVE_JPEG:
- file_type = "jpeg_image_files";
- file_dialog_filter = "*.{jpg,jpeg}";
- break;
- case FFSAVE_SCRIPT:
- file_type = "script_files";
- file_dialog_filter = "*.lsl";
- break;
- case FFSAVE_TGAPNG:
- file_type = "save_texture_image_files";
- file_dialog_filter = "*.{tga,png}";
- break;
- case FFSAVE_WAV:
- file_type = "sound_files";
- file_dialog_filter = "*.wav";
- break;
- case FFSAVE_GLTF:
- file_type = "gltf_asset_file";
- file_dialog_filter = "*.{gltf,glb}";
- break;
+ case FFSAVE_WAV:
+ caption += add_wav_filter_to_gtkchooser(picker);
+ suggest_ext = ".wav";
+ break;
+ case FFSAVE_TGA:
+ caption += add_simple_pattern_filter_to_gtkchooser
+ (picker, "*.tga", LLTrans::getString("targa_image_files") + " (*.tga)");
+ suggest_ext = ".tga";
+ break;
+ case FFSAVE_BMP:
+ caption += add_simple_mime_filter_to_gtkchooser
+ (picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)");
+ suggest_ext = ".bmp";
+ break;
+ case FFSAVE_PNG:
+ caption += add_simple_mime_filter_to_gtkchooser
+ (picker, "image/png", LLTrans::getString("png_image_files") + " (*.png)");
+ suggest_ext = ".png";
+ break;
+ case FFSAVE_TGAPNG:
+ caption += add_save_texture_filter_to_gtkchooser(picker);
+ suggest_ext = ".png";
+ break;
+ case FFSAVE_AVI:
+ caption += add_simple_mime_filter_to_gtkchooser
+ (picker, "video/x-msvideo",
+ LLTrans::getString("avi_movie_file") + " (*.avi)");
+ suggest_ext = ".avi";
+ break;
+ case FFSAVE_ANIM:
+ caption += add_simple_pattern_filter_to_gtkchooser
+ (picker, "*.xaf", LLTrans::getString("xaf_animation_file") + " (*.xaf)");
+ suggest_ext = ".xaf";
+ break;
+ case FFSAVE_XML:
+ caption += add_simple_pattern_filter_to_gtkchooser
+ (picker, "*.xml", LLTrans::getString("xml_file") + " (*.xml)");
+ suggest_ext = ".xml";
+ break;
+ case FFSAVE_RAW:
+ caption += add_simple_pattern_filter_to_gtkchooser
+ (picker, "*.raw", LLTrans::getString("raw_file") + " (*.raw)");
+ suggest_ext = ".raw";
+ break;
+ case FFSAVE_J2C:
+ // *TODO: Should this be 'image/j2c' ?
+ caption += add_simple_mime_filter_to_gtkchooser
+ (picker, "images/jp2",
+ LLTrans::getString("compressed_image_files") + " (*.j2c)");
+ suggest_ext = ".j2c";
+ break;
+ case FFSAVE_SCRIPT:
+ caption += add_script_filter_to_gtkchooser(picker);
+ suggest_ext = ".lsl";
+ break;
+ default:;
+ break;
}
- file_dialog_title = LLTrans::getString("save_file_verb") + " " + LLTrans::getString(file_type);
- file_dialog_filter = LLTrans::getString(file_type) + " \t" + file_dialog_filter;
- }
- else
- {
- std::string file_type("all_files");
- switch ((ELoadFilter) filter)
+
+ gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
+
+ if (filename.empty())
{
- case FFLOAD_ALL:
- break;
- case FFLOAD_WAV:
- file_type = "sound_files";
- file_dialog_filter = "*.wav";
- break;
- case FFLOAD_IMAGE:
- file_type = "image_files";
- file_dialog_filter = "*.{tga,bmp,jpg,jpeg,png}";
- break;
- case FFLOAD_ANIM:
- file_type = "animation_files";
- file_dialog_filter = "*.{bvh,anim}";
- break;
- case FFLOAD_XML:
- file_type = "xml_file";
- file_dialog_filter = "*.xml";
- break;
- case FFLOAD_SLOBJECT:
- file_type = "xml_file";
- file_dialog_filter = "*.slobject";
- break;
- case FFLOAD_RAW:
- file_type = "raw_file";
- file_dialog_filter = "*.raw";
- break;
- case FFLOAD_MODEL:
- case FFLOAD_COLLADA:
- file_type = "collada_files";
- file_dialog_filter = "*.dae";
- break;
- case FFLOAD_SCRIPT:
- file_type = "script_files";
- file_dialog_filter = "*.lsl";
- break;
- case FFLOAD_DICTIONARY:
- file_type = "dictionary_files";
- file_dialog_filter = "*.{dic,xcu}";
- break;
- case FFLOAD_DIRECTORY:
- file_type = "choose_the_directory";
- break;
- case FFLOAD_EXE:
- file_type = "executable_files";
- break;
- case FFLOAD_GLTF:
- case FFLOAD_MATERIAL:
- file_type = "gltf_asset_file";
- file_dialog_filter = "*.{gltg,glb}";
- break;
- case FFLOAD_MATERIAL_TEXTURE:
- file_dialog_filter = "*.{gltf,glb,tga,bmp,jpg,jpeg,png}";
- file_type = "image_files";
- break;
- case FFLOAD_HDRI:
- file_dialog_filter = "*.exr";
+ suggest_name += suggest_ext;
+ gtk_file_chooser_set_current_name
+ (GTK_FILE_CHOOSER(picker),
+ suggest_name.c_str());
}
- if (aType == EType::eOpenMultiple)
+ else
{
- file_dialog_title = LLTrans::getString("load_files");
+ gtk_file_chooser_set_current_name
+ (GTK_FILE_CHOOSER(picker), filename.c_str());
}
- else
+
+ gtk_widget_show_all(GTK_WIDGET(picker));
+
+ gtk_main();
+
+ rtn = (getFileCount() == 1);
+
+ if(rtn && filter == FFSAVE_TGAPNG)
{
- file_dialog_title = LLTrans::getString("load_file_verb") + " " + LLTrans::getString(file_type);
- file_dialog_filter = LLTrans::getString(file_type) + " \t" + file_dialog_filter;
+ std::string selected_file = mFiles.back();
+ mFiles.pop_back();
+ mFiles.push_back(selected_file + mCurrentExtension);
}
}
- flDlg.title(file_dialog_title.c_str());
- flDlg.type(flType);
- if (!file_dialog_filter.empty())
+
+ gViewerWindow->getWindow()->afterDialog();
+
+ return rtn;
+}
+
+bool LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
+{
+ bool rtn = false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if (!check_local_file_access_enabled())
{
- flDlg.filter(file_dialog_filter.c_str());
+ return false;
}
- int res = flDlg.show();
- gViewerWindow->getWindow()->afterDialog();
- if( res == 0 )
+
+ gViewerWindow->getWindow()->beforeDialog();
+
+ reset();
+
+ GtkWindow* picker = buildFilePicker(false, false, "openfile");
+
+ if (picker)
{
- int32_t count = flDlg.count();
- if( count < 0 )
- count = 0;
- for( int32_t i = 0; i < count; ++i )
+ std::string caption = LLTrans::getString("load_file_verb") + " ";
+ std::string filtername = "";
+ switch (filter)
{
- char const *pFile = flDlg.filename(i);
- if( pFile && strlen(pFile) > 0 )
- mFiles.push_back( pFile );
+ case FFLOAD_WAV:
+ filtername = add_wav_filter_to_gtkchooser(picker);
+ break;
+ case FFLOAD_ANIM:
+ filtername = add_anim_filter_to_gtkchooser(picker);
+ break;
+ case FFLOAD_XML:
+ filtername = add_xml_filter_to_gtkchooser(picker);
+ break;
+ case FFLOAD_GLTF:
+ filtername = dead_code_should_blow_up_here(picker);
+ break;
+ case FFLOAD_COLLADA:
+ filtername = add_collada_filter_to_gtkchooser(picker);
+ break;
+ case FFLOAD_IMAGE:
+ filtername = add_imageload_filter_to_gtkchooser(picker);
+ break;
+ case FFLOAD_SCRIPT:
+ filtername = add_script_filter_to_gtkchooser(picker);
+ break;
+ case FFLOAD_DICTIONARY:
+ filtername = add_dictionary_filter_to_gtkchooser(picker);
+ break;
+ default:;
+ break;
}
+
+ caption += filtername;
+
+ gtk_window_set_title(GTK_WINDOW(picker), caption.c_str());
+
+ gtk_widget_show_all(GTK_WIDGET(picker));
+ gtk_main();
+
+ rtn = (getFileCount() == 1);
}
- else if( res == -1 )
+
+ gViewerWindow->getWindow()->afterDialog();
+
+ return rtn;
+}
+
+bool LLFilePicker::getMultipleOpenFiles( ELoadFilter filter, bool blocking)
+{
+ bool rtn = false;
+
+ // if local file browsing is turned off, return without opening dialog
+ if (!check_local_file_access_enabled())
{
- LL_WARNS() << "FLTK failed: " << flDlg.errmsg() << LL_ENDL;
+ return false;
}
- return mFiles.empty()?FALSE:TRUE;
+
+ gViewerWindow->getWindow()->beforeDialog();
+
+ reset();
+
+ GtkWindow* picker = buildFilePicker(false, false, "openfile");
+
+ if (picker)
+ {
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(picker),
+ TRUE);
+
+ gtk_window_set_title(GTK_WINDOW(picker), LLTrans::getString("load_files").c_str());
+
+ gtk_widget_show_all(GTK_WIDGET(picker));
+ gtk_main();
+ rtn = !mFiles.empty();
+ }
+
+ gViewerWindow->getWindow()->afterDialog();
+
+ return rtn;
}
-#else
+
+# else // LL_GTK
+
// Hacky stubs designed to facilitate fake getSaveFile and getOpenFile with
// static results, when we don't have a real filepicker.
@@ -1420,17 +1673,17 @@ bool LLFilePicker::getMultipleOpenFilesModeless(ELoadFilter filter,
return false;
}
-#endif // LL_FLTK
+#endif // LL_GTK
#else // not implemented
-bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename, bool blocking )
+bool LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
{
reset();
return false;
}
-bool LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
+bool LLFilePicker::getOpenFile( ELoadFilter filter )
{
reset();
return false;
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index b99156c61e..4d71a3b392 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -79,6 +79,7 @@ public:
FFLOAD_MATERIAL = 15,
FFLOAD_MATERIAL_TEXTURE = 16,
FFLOAD_HDRI = 17,
+ FFLOAD_LUA = 18,
};
enum ESaveFilter
@@ -173,14 +174,6 @@ private:
void *userdata);
#endif
-#if LL_FLTK
- enum EType
- {
- eSaveFile, eOpenFile, eOpenMultiple
- };
- bool openFileDialog( int32_t filter, bool blocking, EType aType );
-#endif
-
std::vector<std::string> mFiles;
S32 mCurrentFile;
bool mLocked;
diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp
index ff30c83f51..f2345f5c01 100644
--- a/indra/newview/llfloater360capture.cpp
+++ b/indra/newview/llfloater360capture.cpp
@@ -33,6 +33,7 @@
#include "llagentui.h"
#include "llbase64.h"
#include "llcallbacklist.h"
+#include "lldate.h"
#include "llenvironment.h"
#include "llimagejpeg.h"
#include "llmediactrl.h"
@@ -863,15 +864,7 @@ const std::string LLFloater360Capture::generate_proposed_filename()
filename << "_";
// add in the current HH-MM-SS (with leading 0's) so users can easily save many shots in same folder
- std::time_t cur_epoch = std::time(nullptr);
- std::tm* tm_time = std::localtime(&cur_epoch);
- filename << std::setfill('0') << std::setw(4) << (tm_time->tm_year + 1900);
- filename << std::setfill('0') << std::setw(2) << (tm_time->tm_mon + 1);
- filename << std::setfill('0') << std::setw(2) << tm_time->tm_mday;
- filename << "_";
- filename << std::setfill('0') << std::setw(2) << tm_time->tm_hour;
- filename << std::setfill('0') << std::setw(2) << tm_time->tm_min;
- filename << std::setfill('0') << std::setw(2) << tm_time->tm_sec;
+ filename << LLDate::now().toLocalDateString("%Y%m%d_%H%M%S");
// the unusual way we save the output image (originates in the
// embedded browser and not the C++ code) means that the system
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index a87ddfd76e..4608d3913b 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -75,10 +75,10 @@ LLFloaterAuction::LLFloaterAuction(const LLSD& key)
: LLFloater(key),
mParcelID(-1)
{
- mCommitCallbackRegistrar.add("ClickSnapshot", boost::bind(&LLFloaterAuction::onClickSnapshot, this));
- mCommitCallbackRegistrar.add("ClickSellToAnyone", boost::bind(&LLFloaterAuction::onClickSellToAnyone, this));
- mCommitCallbackRegistrar.add("ClickStartAuction", boost::bind(&LLFloaterAuction::onClickStartAuction, this));
- mCommitCallbackRegistrar.add("ClickResetParcel", boost::bind(&LLFloaterAuction::onClickResetParcel, this));
+ mCommitCallbackRegistrar.add("ClickSnapshot", { boost::bind(&LLFloaterAuction::onClickSnapshot, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ClickSellToAnyone", { boost::bind(&LLFloaterAuction::onClickSellToAnyone, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ClickStartAuction", { boost::bind(&LLFloaterAuction::onClickStartAuction, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ClickResetParcel", { boost::bind(&LLFloaterAuction::onClickResetParcel, this), cb_info::UNTRUSTED_BLOCK });
}
// Destroys the object
diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp
index 99f24e161e..d93bd624f5 100644
--- a/indra/newview/llfloaterautoreplacesettings.cpp
+++ b/indra/newview/llfloaterautoreplacesettings.cpp
@@ -422,7 +422,13 @@ bool LLFloaterAutoReplaceSettings::callbackNewListName(const LLSD& notification,
LLSD newList = notification["payload"]["list"];
- if ( response.has("listname") && response["listname"].isString() )
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 1) // Must also match RenameAutoReplaceList
+ {
+ // user cancelled
+ return false;
+ }
+ else if (response.has("listname") && response["listname"].isString() )
{
std::string newName = response["listname"].asString();
LLAutoReplaceSettings::setListName(newList, newName);
@@ -508,12 +514,53 @@ bool LLFloaterAutoReplaceSettings::callbackListNameConflict(const LLSD& notifica
return false;
}
+bool LLFloaterAutoReplaceSettings::callbackRemoveList(const LLSD& notification, const LLSD& response)
+{
+ std::string listName = notification["payload"]["list"];
+
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch (option)
+ {
+ case 1:
+ if (mSettings.removeReplacementList(listName))
+ {
+ LL_INFOS("AutoReplace") << "deleted list '" << listName << "'" << LL_ENDL;
+ mReplacementsList->deleteSelectedItems(); // remove from the scrolling list
+ mSelectedListName.clear();
+ updateListNames();
+ updateListNamesControls();
+ updateReplacementsList();
+ }
+ break;
+ case 0:
+ break;
+
+ default:
+ LL_ERRS("AutoReplace") << "invalid selected option " << option << LL_ENDL;
+ }
+
+ return false;
+}
+
void LLFloaterAutoReplaceSettings::onDeleteList()
{
std::string listName = mListNames->getSelectedValue().asString();
if ( ! listName.empty() )
{
- if ( mSettings.removeReplacementList(listName) )
+ const LLSD* mappings = mSettings.getListEntries(mSelectedListName);
+ if (mappings->size() > 0)
+ {
+ LLSD payload;
+ payload["list"] = listName;
+
+ LLSD args;
+ args["MAP_SIZE"] = llformat("%d",mappings->size());
+ args["LIST_NAME"] = listName;
+
+ LLNotificationsUtil::add("RemoveAutoReplaceList", args, payload,
+ boost::bind(&LLFloaterAutoReplaceSettings::callbackRemoveList, this, _1, _2));
+ }
+ else if ( mSettings.removeReplacementList(listName) )
{
LL_INFOS("AutoReplace")<<"deleted list '"<<listName<<"'"<<LL_ENDL;
mReplacementsList->deleteSelectedItems(); // remove from the scrolling list
diff --git a/indra/newview/llfloaterautoreplacesettings.h b/indra/newview/llfloaterautoreplacesettings.h
index 94a7c00c15..1a8068ab7c 100644
--- a/indra/newview/llfloaterautoreplacesettings.h
+++ b/indra/newview/llfloaterautoreplacesettings.h
@@ -105,6 +105,8 @@ private:
bool callbackNewListName(const LLSD& notification, const LLSD& response);
/// called from the RenameAutoReplaceList notification dialog
bool callbackListNameConflict(const LLSD& notification, const LLSD& response);
+ /// called from the RemoveAutoReplaceList notification dialog
+ bool callbackRemoveList(const LLSD& notification, const LLSD& response);
bool selectedListIsFirst();
bool selectedListIsLast();
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 08a54b7369..196c9e8818 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -111,7 +111,7 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key)
mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA),
mContextConeFadeTime(CONTEXT_CONE_FADE_TIME)
{
- mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this));
+ mCommitCallbackRegistrar.add("Refresh.FriendList", { boost::bind(&LLFloaterAvatarPicker::populateFriend, this), cb_info::UNTRUSTED_THROTTLE });
}
bool LLFloaterAvatarPicker::postBuild()
diff --git a/indra/newview/llfloateravatarrendersettings.cpp b/indra/newview/llfloateravatarrendersettings.cpp
index 9101e6eb29..16e2903324 100644
--- a/indra/newview/llfloateravatarrendersettings.cpp
+++ b/indra/newview/llfloateravatarrendersettings.cpp
@@ -51,7 +51,7 @@ protected:
{
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
- registrar.add("Settings.SetRendering", boost::bind(&LLFloaterAvatarRenderSettings::onCustomAction, mFloaterSettings, _2, mUUIDs.front()));
+ registrar.add("Settings.SetRendering", { boost::bind(&LLFloaterAvatarRenderSettings::onCustomAction, mFloaterSettings, _2, mUUIDs.front()) });
enable_registrar.add("Settings.IsSelected", boost::bind(&LLFloaterAvatarRenderSettings::isActionChecked, mFloaterSettings, _2, mUUIDs.front()));
LLContextMenu* menu = createFromFile("menu_avatar_rendering_settings.xml");
@@ -75,7 +75,7 @@ LLFloaterAvatarRenderSettings::LLFloaterAvatarRenderSettings(const LLSD& key)
{
mContextMenu = new LLSettingsContextMenu(this);
LLRenderMuteList::getInstance()->addObserver(&sAvatarRenderMuteListObserver);
- mCommitCallbackRegistrar.add("Settings.AddNewEntry", boost::bind(&LLFloaterAvatarRenderSettings::onClickAdd, this, _2));
+ mCommitCallbackRegistrar.add("Settings.AddNewEntry", {boost::bind(&LLFloaterAvatarRenderSettings::onClickAdd, this, _2)});
}
LLFloaterAvatarRenderSettings::~LLFloaterAvatarRenderSettings()
diff --git a/indra/newview/llfloaterbeacons.cpp b/indra/newview/llfloaterbeacons.cpp
index 11c1c2a9f2..1b975f3553 100644
--- a/indra/newview/llfloaterbeacons.cpp
+++ b/indra/newview/llfloaterbeacons.cpp
@@ -49,7 +49,7 @@ LLFloaterBeacons::LLFloaterBeacons(const LLSD& seed)
LLPipeline::setRenderHighlights( gSavedSettings.getBOOL("renderhighlights"));
LLPipeline::setRenderBeacons( gSavedSettings.getBOOL("renderbeacons"));
LLPipeline::setRenderMOAPBeacons( gSavedSettings.getBOOL("moapbeacon"));
- mCommitCallbackRegistrar.add("Beacons.UICheck", boost::bind(&LLFloaterBeacons::onClickUICheck, this,_1));
+ mCommitCallbackRegistrar.add("Beacons.UICheck", { boost::bind(&LLFloaterBeacons::onClickUICheck, this,_1) });
}
bool LLFloaterBeacons::postBuild()
diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp
index c09c02d32b..1d670bfb8c 100644
--- a/indra/newview/llfloaterbulkpermission.cpp
+++ b/indra/newview/llfloaterbulkpermission.cpp
@@ -56,12 +56,12 @@ LLFloaterBulkPermission::LLFloaterBulkPermission(const LLSD& seed)
mDone(false)
{
mID.generate();
- mCommitCallbackRegistrar.add("BulkPermission.Ok", boost::bind(&LLFloaterBulkPermission::onOkBtn, this));
- mCommitCallbackRegistrar.add("BulkPermission.Apply", boost::bind(&LLFloaterBulkPermission::onApplyBtn, this));
- mCommitCallbackRegistrar.add("BulkPermission.Close", boost::bind(&LLFloaterBulkPermission::onCloseBtn, this));
- mCommitCallbackRegistrar.add("BulkPermission.CheckAll", boost::bind(&LLFloaterBulkPermission::onCheckAll, this));
- mCommitCallbackRegistrar.add("BulkPermission.UncheckAll", boost::bind(&LLFloaterBulkPermission::onUncheckAll, this));
- mCommitCallbackRegistrar.add("BulkPermission.CommitCopy", boost::bind(&LLFloaterBulkPermission::onCommitCopy, this));
+ mCommitCallbackRegistrar.add("BulkPermission.Ok", { boost::bind(&LLFloaterBulkPermission::onOkBtn, this) });
+ mCommitCallbackRegistrar.add("BulkPermission.Apply", { boost::bind(&LLFloaterBulkPermission::onApplyBtn, this) });
+ mCommitCallbackRegistrar.add("BulkPermission.Close", { boost::bind(&LLFloaterBulkPermission::onCloseBtn, this) });
+ mCommitCallbackRegistrar.add("BulkPermission.CheckAll", { boost::bind(&LLFloaterBulkPermission::onCheckAll, this) });
+ mCommitCallbackRegistrar.add("BulkPermission.UncheckAll", { boost::bind(&LLFloaterBulkPermission::onUncheckAll, this) });
+ mCommitCallbackRegistrar.add("BulkPermission.CommitCopy", { boost::bind(&LLFloaterBulkPermission::onCommitCopy, this) });
}
bool LLFloaterBulkPermission::postBuild()
diff --git a/indra/newview/llfloaterbulkupload.cpp b/indra/newview/llfloaterbulkupload.cpp
index b898cb28b6..e3664c61bf 100644
--- a/indra/newview/llfloaterbulkupload.cpp
+++ b/indra/newview/llfloaterbulkupload.cpp
@@ -41,6 +41,8 @@ LLFloaterBulkUpload::LLFloaterBulkUpload(const LLSD& key)
mUploadCost = key["upload_cost"].asInteger();
mUploadCount = key["upload_count"].asInteger();
mHas2kTextures = key["has_2k_textures"].asBoolean();
+ mDest = key["dest"].asUUID();
+
if (key["files"].isArray())
{
const LLSD& files = key["files"];
@@ -125,7 +127,7 @@ void LLFloaterBulkUpload::onUpload2KCheckBox()
void LLFloaterBulkUpload::onClickUpload()
{
- do_bulk_upload(mFiles, mAllow2kTextures);
+ do_bulk_upload(mFiles, mAllow2kTextures, mDest);
closeFloater();
}
diff --git a/indra/newview/llfloaterbulkupload.h b/indra/newview/llfloaterbulkupload.h
index d07dc8eabe..48e07b664f 100644
--- a/indra/newview/llfloaterbulkupload.h
+++ b/indra/newview/llfloaterbulkupload.h
@@ -61,6 +61,7 @@ private:
bool mHas2kTextures = false;
S32 mUploadCost = 0;
S32 mUploadCount = 0;
+ LLUUID mDest = LLUUID::null;
};
#endif
diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp
index 162ad5e108..2a4f1ddd12 100644
--- a/indra/newview/llfloaterbump.cpp
+++ b/indra/newview/llfloaterbump.cpp
@@ -51,18 +51,18 @@
LLFloaterBump::LLFloaterBump(const LLSD& key)
: LLFloater(key)
{
- mCommitCallbackRegistrar.add("Avatar.SendIM", boost::bind(&LLFloaterBump::startIM, this));
- mCommitCallbackRegistrar.add("Avatar.ReportAbuse", boost::bind(&LLFloaterBump::reportAbuse, this));
- mCommitCallbackRegistrar.add("ShowAgentProfile", boost::bind(&LLFloaterBump::showProfile, this));
- mCommitCallbackRegistrar.add("Avatar.InviteToGroup", boost::bind(&LLFloaterBump::inviteToGroup, this));
- mCommitCallbackRegistrar.add("Avatar.Call", boost::bind(&LLFloaterBump::startCall, this));
- mEnableCallbackRegistrar.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
- mCommitCallbackRegistrar.add("Avatar.AddFriend", boost::bind(&LLFloaterBump::addFriend, this));
+ mCommitCallbackRegistrar.add("Avatar.SendIM", { boost::bind(&LLFloaterBump::startIM, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("Avatar.ReportAbuse", { boost::bind(&LLFloaterBump::reportAbuse, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("ShowAgentProfile", { boost::bind(&LLFloaterBump::showProfile, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("Avatar.InviteToGroup", { boost::bind(&LLFloaterBump::inviteToGroup, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("Avatar.Call", { boost::bind(&LLFloaterBump::startCall, this), cb_info::UNTRUSTED_BLOCK });
+ mEnableCallbackRegistrar.add("Avatar.EnableCall", { boost::bind(&LLFloaterBump::canCall, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Avatar.AddFriend", { boost::bind(&LLFloaterBump::addFriend, this), cb_info::UNTRUSTED_THROTTLE });
mEnableCallbackRegistrar.add("Avatar.EnableAddFriend", boost::bind(&LLFloaterBump::enableAddFriend, this));
- mCommitCallbackRegistrar.add("Avatar.Mute", boost::bind(&LLFloaterBump::muteAvatar, this));
+ mCommitCallbackRegistrar.add("Avatar.Mute", { boost::bind(&LLFloaterBump::muteAvatar, this), cb_info::UNTRUSTED_BLOCK });
mEnableCallbackRegistrar.add("Avatar.EnableMute", boost::bind(&LLFloaterBump::enableMute, this));
- mCommitCallbackRegistrar.add("PayObject", boost::bind(&LLFloaterBump::payAvatar, this));
- mCommitCallbackRegistrar.add("Tools.LookAtSelection", boost::bind(&LLFloaterBump::zoomInAvatar, this));
+ mCommitCallbackRegistrar.add("PayObject", { boost::bind(&LLFloaterBump::payAvatar, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Tools.LookAtSelection", { boost::bind(&LLFloaterBump::zoomInAvatar, this) });
}
@@ -214,6 +214,11 @@ void LLFloaterBump::startCall()
LLAvatarActions::startCall(mItemUUID);
}
+bool LLFloaterBump::canCall()
+{
+ return LLAvatarActions::canCallTo(mItemUUID);
+}
+
void LLFloaterBump::reportAbuse()
{
LLFloaterReporter::showFromAvatar(mItemUUID, "av_name");
diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h
index 53e730d73f..48d6f7e33e 100644
--- a/indra/newview/llfloaterbump.h
+++ b/indra/newview/llfloaterbump.h
@@ -52,6 +52,7 @@ public:
void startIM();
void startCall();
+ bool canCall();
void reportAbuse();
void showProfile();
void addFriend();
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index b94c31ec04..7450be45f1 100644
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -118,8 +118,8 @@ std::string STATUS[] =
//-----------------------------------------------------------------------------
// LLFloaterBvhPreview()
//-----------------------------------------------------------------------------
-LLFloaterBvhPreview::LLFloaterBvhPreview(const std::string& filename) :
- LLFloaterNameDesc(filename)
+LLFloaterBvhPreview::LLFloaterBvhPreview(const LLSD& args) :
+ LLFloaterNameDesc(args)
{
mLastMouseX = 0;
mLastMouseY = 0;
@@ -1028,7 +1028,8 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata)
LLFloaterPerms::getNextOwnerPerms("Uploads"),
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
- expected_upload_cost));
+ expected_upload_cost,
+ floaterp->mDestinationFolderId));
upload_new_resource(assetUploadInfo);
}
diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h
index ae64521492..c6b75c00b2 100644
--- a/indra/newview/llfloaterbvhpreview.h
+++ b/indra/newview/llfloaterbvhpreview.h
@@ -70,7 +70,7 @@ protected:
class LLFloaterBvhPreview : public LLFloaterNameDesc
{
public:
- LLFloaterBvhPreview(const std::string& filename);
+ LLFloaterBvhPreview(const LLSD& args);
virtual ~LLFloaterBvhPreview();
bool postBuild();
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index 76ac730362..f20858452a 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -169,11 +169,11 @@ static LLPanelInjector<LLPanelCameraZoom> t_camera_zoom_panel("camera_zoom_panel
void LLPanelCameraZoom::onCreate()
{
- mCommitCallbackRegistrar.add("Zoom.minus", boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this));
- mCommitCallbackRegistrar.add("Zoom.plus", boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this));
- mCommitCallbackRegistrar.add("Slider.value_changed", boost::bind(&LLPanelCameraZoom::onSliderValueChanged, this));
- mCommitCallbackRegistrar.add("Camera.track", boost::bind(&LLPanelCameraZoom::onCameraTrack, this));
- mCommitCallbackRegistrar.add("Camera.rotate", boost::bind(&LLPanelCameraZoom::onCameraRotate, this));
+ mCommitCallbackRegistrar.add("Zoom.minus", { boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this) });
+ mCommitCallbackRegistrar.add("Zoom.plus", { boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this) });
+ mCommitCallbackRegistrar.add("Slider.value_changed", { boost::bind(&LLPanelCameraZoom::onSliderValueChanged, this) });
+ mCommitCallbackRegistrar.add("Camera.track", { boost::bind(&LLPanelCameraZoom::onCameraTrack, this) });
+ mCommitCallbackRegistrar.add("Camera.rotate", { boost::bind(&LLPanelCameraZoom::onCameraRotate, this) });
}
bool LLPanelCameraZoom::postBuild()
@@ -461,9 +461,9 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
mPrevMode(CAMERA_CTRL_MODE_PAN)
{
LLHints::getInstance()->registerHintTarget("view_popup", getHandle());
- mCommitCallbackRegistrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
- mCommitCallbackRegistrar.add("CameraPresets.Save", boost::bind(&LLFloaterCamera::onSavePreset, this));
- mCommitCallbackRegistrar.add("CameraPresets.ShowPresetsList", boost::bind(&LLFloaterReg::showInstance, "camera_presets", LLSD(), false));
+ mCommitCallbackRegistrar.add("CameraPresets.ChangeView", {boost::bind(&LLFloaterCamera::onClickCameraItem, _2)});
+ mCommitCallbackRegistrar.add("CameraPresets.Save", {boost::bind(&LLFloaterCamera::onSavePreset, this)});
+ mCommitCallbackRegistrar.add("CameraPresets.ShowPresetsList", {boost::bind(&LLFloaterReg::showInstance, "camera_presets", LLSD(), false)});
}
// virtual
diff --git a/indra/newview/llfloatercamerapresets.cpp b/indra/newview/llfloatercamerapresets.cpp
index b033af2564..d527541b76 100644
--- a/indra/newview/llfloatercamerapresets.cpp
+++ b/indra/newview/llfloatercamerapresets.cpp
@@ -90,8 +90,8 @@ LLCameraPresetFlatItem::LLCameraPresetFlatItem(const std::string &preset_name, b
mPresetName(preset_name),
mIsDefaultPrest(is_default)
{
- mCommitCallbackRegistrar.add("CameraPresets.Delete", boost::bind(&LLCameraPresetFlatItem::onDeleteBtnClick, this));
- mCommitCallbackRegistrar.add("CameraPresets.Reset", boost::bind(&LLCameraPresetFlatItem::onResetBtnClick, this));
+ mCommitCallbackRegistrar.add("CameraPresets.Delete", { boost::bind(&LLCameraPresetFlatItem::onDeleteBtnClick, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("CameraPresets.Reset", { boost::bind(&LLCameraPresetFlatItem::onResetBtnClick, this), cb_info::UNTRUSTED_BLOCK });
buildFromFile("panel_camera_preset_item.xml");
}
diff --git a/indra/newview/llfloaterconversationlog.cpp b/indra/newview/llfloaterconversationlog.cpp
index 97399c9cf7..dc0f4ae555 100644
--- a/indra/newview/llfloaterconversationlog.cpp
+++ b/indra/newview/llfloaterconversationlog.cpp
@@ -35,7 +35,7 @@ LLFloaterConversationLog::LLFloaterConversationLog(const LLSD& key)
: LLFloater(key),
mConversationLogList(NULL)
{
- mCommitCallbackRegistrar.add("CallLog.Action", boost::bind(&LLFloaterConversationLog::onCustomAction, this, _2));
+ mCommitCallbackRegistrar.add("CallLog.Action", { boost::bind(&LLFloaterConversationLog::onCustomAction, this, _2) });
mEnableCallbackRegistrar.add("CallLog.Check", boost::bind(&LLFloaterConversationLog::isActionChecked, this, _2));
}
diff --git a/indra/newview/llfloatereditenvironmentbase.h b/indra/newview/llfloatereditenvironmentbase.h
index 37fda5d33e..41192f3d30 100644
--- a/indra/newview/llfloatereditenvironmentbase.h
+++ b/indra/newview/llfloatereditenvironmentbase.h
@@ -133,7 +133,8 @@ protected:
LLSettingsEditPanel() :
LLPanel(),
mIsDirty(false),
- mOnDirtyChanged()
+ mOnDirtyChanged(),
+ mCanEdit(false)
{}
private:
diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp
index fd58cd8aaf..626f06ce7e 100644
--- a/indra/newview/llfloatereditextdaycycle.cpp
+++ b/indra/newview/llfloatereditextdaycycle.cpp
@@ -183,8 +183,8 @@ LLFloaterEditExtDayCycle::LLFloaterEditExtDayCycle(const LLSD &key) :
mLoadTrack(nullptr),
mClearTrack(nullptr)
{
- mCommitCallbackRegistrar.add(EVNT_DAYTRACK, [this](LLUICtrl *ctrl, const LLSD &data) { onTrackSelectionCallback(data); });
- mCommitCallbackRegistrar.add(EVNT_PLAY, [this](LLUICtrl *ctrl, const LLSD &data) { onPlayActionCallback(data); });
+ mCommitCallbackRegistrar.add(EVNT_DAYTRACK, { [this](LLUICtrl *ctrl, const LLSD &data) { onTrackSelectionCallback(data); }});
+ mCommitCallbackRegistrar.add(EVNT_PLAY, { [this](LLUICtrl *ctrl, const LLSD &data) { onPlayActionCallback(data); }});
mScratchSky = LLSettingsVOSky::buildDefaultSky();
mScratchWater = LLSettingsVOWater::buildDefaultWater();
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index 936096d8fe..0ff958c19b 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -122,11 +122,11 @@ LLFloaterGesture::LLFloaterGesture(const LLSD& key)
mObserver = new LLFloaterGestureObserver(this);
LLGestureMgr::instance().addObserver(mObserver);
- mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
- mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this));
- mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2));
- mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this));
- mCommitCallbackRegistrar.add("Gesture.Action.Rename", boost::bind(&LLFloaterGesture::onRenameSelected, this));
+ mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", { boost::bind(&LLFloaterGesture::onActivateBtnClick, this) });
+ mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", { boost::bind(&LLFloaterGesture::onClickEdit, this) });
+ mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", { boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2) });
+ mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", { boost::bind(&LLFloaterGesture::addToCurrentOutFit, this) });
+ mCommitCallbackRegistrar.add("Gesture.Action.Rename", { boost::bind(&LLFloaterGesture::onRenameSelected, this) });
mEnableCallbackRegistrar.add("Gesture.EnableAction", boost::bind(&LLFloaterGesture::isActionEnabled, this, _2));
}
diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp
index a127f5d43e..002fb3996f 100644
--- a/indra/newview/llfloatergltfasseteditor.cpp
+++ b/indra/newview/llfloatergltfasseteditor.cpp
@@ -46,8 +46,8 @@ LLFloaterGLTFAssetEditor::LLFloaterGLTFAssetEditor(const LLSD& key)
{
setTitle("GLTF Asset Editor (WIP)");
- mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", [this](LLUICtrl* ctrl, const LLSD& data) { onMenuDoToSelected(data); });
- mEnableCallbackRegistrar.add("PanelObject.menuEnable", [this](LLUICtrl* ctrl, const LLSD& data) { return onMenuEnableItem(data); });
+ mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", { [this](LLUICtrl* ctrl, const LLSD& data) { onMenuDoToSelected(data); }});
+ mEnableCallbackRegistrar.add("PanelObject.menuEnable", { [this](LLUICtrl* ctrl, const LLSD& data) { return onMenuEnableItem(data); }});
}
LLFloaterGLTFAssetEditor::~LLFloaterGLTFAssetEditor()
diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp
index 6c1d5b5cca..f2884c3a6e 100644
--- a/indra/newview/llfloatergodtools.cpp
+++ b/indra/newview/llfloatergodtools.cpp
@@ -431,15 +431,15 @@ const F32 PRICE_PER_METER_DEFAULT = 1.f;
LLPanelRegionTools::LLPanelRegionTools()
: LLPanel()
{
- mCommitCallbackRegistrar.add("RegionTools.ChangeAnything", boost::bind(&LLPanelRegionTools::onChangeAnything, this));
- mCommitCallbackRegistrar.add("RegionTools.ChangePrelude", boost::bind(&LLPanelRegionTools::onChangePrelude, this));
- mCommitCallbackRegistrar.add("RegionTools.BakeTerrain", boost::bind(&LLPanelRegionTools::onBakeTerrain, this));
- mCommitCallbackRegistrar.add("RegionTools.RevertTerrain", boost::bind(&LLPanelRegionTools::onRevertTerrain, this));
- mCommitCallbackRegistrar.add("RegionTools.SwapTerrain", boost::bind(&LLPanelRegionTools::onSwapTerrain, this));
- mCommitCallbackRegistrar.add("RegionTools.Refresh", boost::bind(&LLPanelRegionTools::onRefresh, this));
- mCommitCallbackRegistrar.add("RegionTools.ApplyChanges", boost::bind(&LLPanelRegionTools::onApplyChanges, this));
- mCommitCallbackRegistrar.add("RegionTools.SelectRegion", boost::bind(&LLPanelRegionTools::onSelectRegion, this));
- mCommitCallbackRegistrar.add("RegionTools.SaveState", boost::bind(&LLPanelRegionTools::onSaveState, this));
+ mCommitCallbackRegistrar.add("RegionTools.ChangeAnything", { boost::bind(&LLPanelRegionTools::onChangeAnything, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.ChangePrelude", { boost::bind(&LLPanelRegionTools::onChangePrelude, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.BakeTerrain", { boost::bind(&LLPanelRegionTools::onBakeTerrain, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.RevertTerrain", { boost::bind(&LLPanelRegionTools::onRevertTerrain, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.SwapTerrain", { boost::bind(&LLPanelRegionTools::onSwapTerrain, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.Refresh", { boost::bind(&LLPanelRegionTools::onRefresh, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.ApplyChanges", { boost::bind(&LLPanelRegionTools::onApplyChanges, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.SelectRegion", { boost::bind(&LLPanelRegionTools::onSelectRegion, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("RegionTools.SaveState", { boost::bind(&LLPanelRegionTools::onSaveState, this), cb_info::UNTRUSTED_BLOCK });
}
bool LLPanelRegionTools::postBuild()
@@ -854,7 +854,8 @@ void LLPanelRegionTools::onSelectRegion()
LLPanelGridTools::LLPanelGridTools() :
LLPanel()
{
- mCommitCallbackRegistrar.add("GridTools.FlushMapVisibilityCaches", boost::bind(&LLPanelGridTools::onClickFlushMapVisibilityCaches, this));
+ mCommitCallbackRegistrar.add("GridTools.FlushMapVisibilityCaches",
+ { boost::bind(&LLPanelGridTools::onClickFlushMapVisibilityCaches, this), cb_info::UNTRUSTED_BLOCK });
}
// Destroys the object
@@ -929,15 +930,15 @@ LLPanelObjectTools::LLPanelObjectTools()
: LLPanel(),
mTargetAvatar()
{
- mCommitCallbackRegistrar.add("ObjectTools.ChangeAnything", boost::bind(&LLPanelObjectTools::onChangeAnything, this));
- mCommitCallbackRegistrar.add("ObjectTools.DeletePublicOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeletePublicOwnedBy, this));
- mCommitCallbackRegistrar.add("ObjectTools.DeleteAllScriptedOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy, this));
- mCommitCallbackRegistrar.add("ObjectTools.DeleteAllOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeleteAllOwnedBy, this));
- mCommitCallbackRegistrar.add("ObjectTools.ApplyChanges", boost::bind(&LLPanelObjectTools::onApplyChanges, this));
- mCommitCallbackRegistrar.add("ObjectTools.Set", boost::bind(&LLPanelObjectTools::onClickSet, this));
- mCommitCallbackRegistrar.add("ObjectTools.GetTopColliders", boost::bind(&LLPanelObjectTools::onGetTopColliders, this));
- mCommitCallbackRegistrar.add("ObjectTools.GetTopScripts", boost::bind(&LLPanelObjectTools::onGetTopScripts, this));
- mCommitCallbackRegistrar.add("ObjectTools.GetScriptDigest", boost::bind(&LLPanelObjectTools::onGetScriptDigest, this));
+ mCommitCallbackRegistrar.add("ObjectTools.ChangeAnything", { boost::bind(&LLPanelObjectTools::onChangeAnything, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.DeletePublicOwnedBy", { boost::bind(&LLPanelObjectTools::onClickDeletePublicOwnedBy, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.DeleteAllScriptedOwnedBy", { boost::bind(&LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.DeleteAllOwnedBy", { boost::bind(&LLPanelObjectTools::onClickDeleteAllOwnedBy, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.ApplyChanges", { boost::bind(&LLPanelObjectTools::onApplyChanges, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.Set", { boost::bind(&LLPanelObjectTools::onClickSet, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.GetTopColliders", { boost::bind(&LLPanelObjectTools::onGetTopColliders, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.GetTopScripts", { boost::bind(&LLPanelObjectTools::onGetTopScripts, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ObjectTools.GetScriptDigest", { boost::bind(&LLPanelObjectTools::onGetScriptDigest, this), cb_info::UNTRUSTED_BLOCK });
}
// Destroys the object
@@ -1224,7 +1225,7 @@ const std::string AGENT_REGION = "Agent Region";
LLPanelRequestTools::LLPanelRequestTools():
LLPanel()
{
- mCommitCallbackRegistrar.add("GodTools.Request", boost::bind(&LLPanelRequestTools::onClickRequest, this));
+ mCommitCallbackRegistrar.add("GodTools.Request", {boost::bind(&LLPanelRequestTools::onClickRequest, this), cb_info::UNTRUSTED_BLOCK });
}
LLPanelRequestTools::~LLPanelRequestTools()
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 989e1d8d04..f254fdafaf 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -72,8 +72,8 @@ const S32 PREVIEW_TEXTURE_HEIGHT = 320;
//-----------------------------------------------------------------------------
// LLFloaterImagePreview()
//-----------------------------------------------------------------------------
-LLFloaterImagePreview::LLFloaterImagePreview(const std::string& filename) :
- LLFloaterNameDesc(filename),
+LLFloaterImagePreview::LLFloaterImagePreview(const LLSD& args) :
+ LLFloaterNameDesc(args),
mAvatarPreview(NULL),
mSculptedPreview(NULL),
diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h
index ed395722de..9bc57246cf 100644
--- a/indra/newview/llfloaterimagepreview.h
+++ b/indra/newview/llfloaterimagepreview.h
@@ -110,7 +110,7 @@ protected:
class LLFloaterImagePreview : public LLFloaterNameDesc
{
public:
- LLFloaterImagePreview(const std::string& filename);
+ LLFloaterImagePreview(const LLSD& args);
virtual ~LLFloaterImagePreview();
bool postBuild() override;
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index e55bf50724..ed24a8af57 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -76,14 +76,14 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param
mConversationEventQueue()
{
mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2));
- mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2));
+ mCommitCallbackRegistrar.add("IMFloaterContainer.Action", { boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2) });
mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMContainer::checkContextMenuItem, this, _2));
mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMContainer::enableContextMenuItem, this, _2));
mEnableCallbackRegistrar.add("Avatar.VisibleItem", boost::bind(&LLFloaterIMContainer::visibleContextMenuItem, this, _2));
- mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMContainer::doToSelected, this, _2));
+ mCommitCallbackRegistrar.add("Avatar.DoToSelected", { boost::bind(&LLFloaterIMContainer::doToSelected, this, _2) });
- mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&LLFloaterIMContainer::doToSelectedGroup, this, _2));
+ mCommitCallbackRegistrar.add("Group.DoToSelected", { boost::bind(&LLFloaterIMContainer::doToSelectedGroup, this, _2) });
// Firstly add our self to IMSession observers, so we catch session events
LLIMMgr::getInstance()->addSessionObserver(this);
@@ -1592,15 +1592,15 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v
}
else if ("can_call" == item)
{
+ if (is_single_select)
+ {
+ return LLAvatarActions::canCallTo(single_id);
+ }
return LLAvatarActions::canCall();
}
else if ("can_open_voice_conversation" == item)
{
- return is_single_select && LLAvatarActions::canCall();
- }
- else if ("can_open_voice_conversation" == item)
- {
- return is_single_select && LLAvatarActions::canCall();
+ return is_single_select && LLAvatarActions::canCallTo(single_id);
}
else if ("can_zoom_in" == item)
{
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 28c651f0cd..6c3e8391cd 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -52,6 +52,7 @@
#include "llfirstuse.h"
#include "llfloaterimnearbychat.h"
+#include "llfloaterimnearbychatlistener.h"
#include "llagent.h" // gAgent
#include "llgesturemgr.h"
#include "llmultigesture.h"
@@ -71,6 +72,8 @@
S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0;
+static LLFloaterIMNearbyChatListener sChatListener;
+
constexpr S32 EXPANDED_HEIGHT = 266;
constexpr S32 COLLAPSED_HEIGHT = 60;
constexpr S32 EXPANDED_MIN_HEIGHT = 150;
@@ -106,7 +109,7 @@ LLFloaterIMNearbyChat::LLFloaterIMNearbyChat(const LLSD& llsd)
// Required by LLFloaterIMSessionTab::mGearBtn
// But nearby floater has no 'per agent' menu items,
mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&cb_do_nothing));
- mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&cb_do_nothing));
+ mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", { boost::bind(&cb_do_nothing) });
mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&cb_do_nothing));
mMinFloaterHeight = EXPANDED_MIN_HEIGHT;
diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp
index c920a3c898..20bf896562 100644
--- a/indra/newview/llfloaterimnearbychathandler.cpp
+++ b/indra/newview/llfloaterimnearbychathandler.cpp
@@ -300,12 +300,13 @@ void LLFloaterIMNearbyChatScreenChannel::addChat(LLSD& chat)
{
LLUUID fromID = chat["from_id"].asUUID(); // agent id or object id
std::string from = chat["from"].asString();
+ bool is_lua = chat["is_lua"].asBoolean();
LLToast* toast = m_active_toasts[0].get();
if (toast)
{
LLFloaterIMNearbyChatToastPanel* panel = dynamic_cast<LLFloaterIMNearbyChatToastPanel*>(toast->getPanel());
- if (panel && panel->messageID() == fromID && panel->getFromName() == from && panel->canAddText())
+ if (panel && panel->messageID() == fromID && panel->getFromName() == from && panel->isFromScript() == is_lua && panel->canAddText())
{
panel->addMessage(chat);
toast->reshapeToPanel();
@@ -596,17 +597,22 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
{
// Handle IRC styled messages.
std::string toast_msg;
+ std::string msg_text = without_LUA_PREFIX(chat_msg.mText, chat_msg.mIsScript);
if (chat_msg.mChatStyle == CHAT_STYLE_IRC)
{
+ if (chat_msg.mIsScript)
+ {
+ toast_msg += LLTrans::getString("ScriptStr");
+ }
if (!chat_msg.mFromName.empty())
{
toast_msg += chat_msg.mFromName;
}
- toast_msg += chat_msg.mText.substr(3);
+ toast_msg += msg_text.substr(3);
}
else
{
- toast_msg = chat_msg.mText;
+ toast_msg = msg_text;
}
bool chat_overlaps = false;
@@ -666,6 +672,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
chat["color_alpha"] = r_color_alpha;
chat["font_size"] = (S32)LLViewerChat::getChatFontSize() ;
chat["message"] = toast_msg;
+ chat["is_lua"] = chat_msg.mIsScript;
channel->addChat(chat);
}
diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp
index 43173d3680..0618741cc4 100644
--- a/indra/newview/llfloaterimnearbychatlistener.cpp
+++ b/indra/newview/llfloaterimnearbychatlistener.cpp
@@ -34,12 +34,14 @@
#include "llagent.h"
#include "llchat.h"
#include "llviewercontrol.h"
+#include "stringize.h"
+static const F32 CHAT_THROTTLE_PERIOD = 1.f;
-LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar)
+LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener()
: LLEventAPI("LLChatBar",
"LLChatBar listener to (e.g.) sendChat, etc."),
- mChatbar(chatbar)
+ mLastThrottleTime(0)
{
add("sendChat",
"Send chat to the simulator:\n"
@@ -51,10 +53,19 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyCh
// "sendChat" command
-void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const
+void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data)
{
+ F64 cur_time = LLTimer::getElapsedSeconds();
+
+ if (cur_time < mLastThrottleTime + CHAT_THROTTLE_PERIOD)
+ {
+ LL_DEBUGS("LLFloaterIMNearbyChatListener") << "'sendChat' was throttled" << LL_ENDL;
+ return;
+ }
+ mLastThrottleTime = cur_time;
+
// Extract the data
- std::string chat_text = chat_data["message"].asString();
+ std::string chat_text = LUA_PREFIX + chat_data["message"].asString();
S32 channel = 0;
if (chat_data.has("channel"))
@@ -81,20 +92,14 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const
}
// Have to prepend /42 style channel numbers
- std::string chat_to_send;
- if (channel == 0)
- {
- chat_to_send = chat_text;
- }
- else
+ if (channel)
{
- chat_to_send += "/";
- chat_to_send += chat_data["channel"].asString();
- chat_to_send += " ";
- chat_to_send += chat_text;
+ chat_text = stringize("/", chat_data["channel"].asString(), " ", chat_text);
}
// Send it as if it was typed in
- mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, ((bool)(channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim"));
+ LLFloaterIMNearbyChat::sendChatFromViewer(chat_text, type_o_chat,
+ (channel == 0) &&
+ gSavedSettings.getBOOL("PlayChatAnim"));
}
diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h
index 96184d95b3..18a8bacfaa 100644
--- a/indra/newview/llfloaterimnearbychatlistener.h
+++ b/indra/newview/llfloaterimnearbychatlistener.h
@@ -38,12 +38,12 @@ class LLFloaterIMNearbyChat;
class LLFloaterIMNearbyChatListener : public LLEventAPI
{
public:
- LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar);
+ LLFloaterIMNearbyChatListener();
private:
- void sendChat(LLSD const & chat_data) const;
+ void sendChat(LLSD const & chat_data);
- LLFloaterIMNearbyChat & mChatbar;
+ F64 mLastThrottleTime{ 0.0 };
};
#endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 97e0d01b52..e85aac3810 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -92,7 +92,7 @@ LLFloaterIMSession::LLFloaterIMSession(const LLUUID& session_id)
LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this);
mEnableCallbackRegistrar.add("Avatar.EnableGearItem", boost::bind(&LLFloaterIMSession::enableGearMenuItem, this, _2));
- mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", boost::bind(&LLFloaterIMSession::GearDoToSelected, this, _2));
+ mCommitCallbackRegistrar.add("Avatar.GearDoToSelected", { boost::bind(&LLFloaterIMSession::GearDoToSelected, this, _2), cb_info::UNTRUSTED_BLOCK });
mEnableCallbackRegistrar.add("Avatar.CheckGearItem", boost::bind(&LLFloaterIMSession::checkGearMenuItem, this, _2));
mVoiceChannelChanged = LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMSession::onVoiceChannelChanged, this, _1));
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index fe0916bf15..0855a628fb 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -39,6 +39,7 @@
#include "llchicletbar.h"
#include "lldraghandle.h"
#include "llemojidictionary.h"
+#include "llemojihelper.h"
#include "llfloaterreg.h"
#include "llfloateremojipicker.h"
#include "llfloaterimsession.h"
@@ -82,7 +83,7 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
mCommitCallbackRegistrar.add("IMSession.Menu.Action",
- boost::bind(&LLFloaterIMSessionTab::onIMSessionMenuItemClicked, this, _2));
+ { boost::bind(&LLFloaterIMSessionTab::onIMSessionMenuItemClicked, this, _2) });
mEnableCallbackRegistrar.add("IMSession.Menu.CompactExpandedModes.CheckItem",
boost::bind(&LLFloaterIMSessionTab::onIMCompactExpandedMenuItemCheck, this, _2));
mEnableCallbackRegistrar.add("IMSession.Menu.ShowModes.CheckItem",
@@ -93,8 +94,8 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
// Right click menu handling
mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMSessionTab::checkContextMenuItem, this, _2));
mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2));
- mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2));
- mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing));
+ mCommitCallbackRegistrar.add("Avatar.DoToSelected", { boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2) });
+ mCommitCallbackRegistrar.add("Group.DoToSelected", { boost::bind(&cb_group_do_nothing) });
mMinFloaterHeight = getMinHeight();
}
@@ -298,6 +299,8 @@ bool LLFloaterIMSessionTab::postBuild()
mEmojiPickerShowBtn = getChild<LLButton>("emoji_picker_show_btn");
mEmojiPickerShowBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnClicked(); });
+ mEmojiPickerShowBtn->setMouseDownCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnDown(); });
+ mEmojiCloseConn = LLEmojiHelper::instance().setCloseCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerClosed(); });
mGearBtn = getChild<LLButton>("gear_btn");
mAddBtn = getChild<LLButton>("add_btn");
@@ -526,8 +529,43 @@ void LLFloaterIMSessionTab::onEmojiRecentPanelToggleBtnClicked()
void LLFloaterIMSessionTab::onEmojiPickerShowBtnClicked()
{
- mInputEditor->setFocus(true);
- mInputEditor->showEmojiHelper();
+ if (!mEmojiPickerShowBtn->getToggleState())
+ {
+ mInputEditor->hideEmojiHelper();
+ mInputEditor->setFocus(true);
+ mInputEditor->showEmojiHelper();
+ mEmojiPickerShowBtn->setToggleState(true); // in case hideEmojiHelper closed a visible instance
+ }
+ else
+ {
+ mInputEditor->hideEmojiHelper();
+ mEmojiPickerShowBtn->setToggleState(false);
+ }
+}
+
+void LLFloaterIMSessionTab::onEmojiPickerShowBtnDown()
+{
+ if (mEmojiHelperLastCallbackFrame == LLFrameTimer::getFrameCount())
+ {
+ // Helper gets closed by focus lost event on Down before before onEmojiPickerShowBtnDown
+ // triggers.
+ // If this condition is true, user pressed button and it was 'toggled' during press,
+ // restore 'toggled' state so that button will not reopen helper.
+ mEmojiPickerShowBtn->setToggleState(true);
+ }
+}
+
+void LLFloaterIMSessionTab::onEmojiPickerClosed()
+{
+ if (mEmojiPickerShowBtn->getToggleState())
+ {
+ mEmojiPickerShowBtn->setToggleState(false);
+ // Helper gets closed by focus lost event on Down before onEmojiPickerShowBtnDown
+ // triggers. If mEmojiHelperLastCallbackFrame is set and matches Down, means close
+ // was triggered by user's press.
+ // A bit hacky, but I can't think of a better way to handle this without rewriting helper.
+ mEmojiHelperLastCallbackFrame = LLFrameTimer::getFrameCount();
+ }
}
void LLFloaterIMSessionTab::initEmojiRecentPanel()
@@ -591,8 +629,19 @@ void LLFloaterIMSessionTab::deleteAllChildren()
std::string LLFloaterIMSessionTab::appendTime()
{
- std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:"
- "[" + LLTrans::getString("TimeMin") + "]";
+ std::string timeStr;
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ if (use_24h)
+ {
+ timeStr = "[" + LLTrans::getString("TimeHour") + "]:"
+ "[" + LLTrans::getString("TimeMin") + "]";
+ }
+ else
+ {
+ timeStr = "[" + LLTrans::getString("TimeHour12") + "]:"
+ "[" + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeAMPM") + "]";
+ }
LLSD substitution;
substitution["datetime"] = (S32)time_corrected();
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index bee5c8c2c4..890c920bbe 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -227,6 +227,8 @@ private:
void onEmojiRecentPanelToggleBtnClicked();
void onEmojiPickerShowBtnClicked();
+ void onEmojiPickerShowBtnDown();
+ void onEmojiPickerClosed();
void initEmojiRecentPanel();
void onEmojiRecentPanelFocusReceived();
void onEmojiRecentPanelFocusLost();
@@ -241,6 +243,9 @@ private:
S32 mInputEditorPad;
S32 mChatLayoutPanelHeight;
S32 mFloaterHeight;
+
+ boost::signals2::connection mEmojiCloseConn;
+ U32 mEmojiHelperLastCallbackFrame = { 0 };
};
diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp
index 4f993ca0e1..5dea46843c 100644
--- a/indra/newview/llfloaterinspect.cpp
+++ b/indra/newview/llfloaterinspect.cpp
@@ -51,9 +51,9 @@ LLFloaterInspect::LLFloaterInspect(const LLSD& key)
mOwnerNameCacheConnection(),
mCreatorNameCacheConnection()
{
- mCommitCallbackRegistrar.add("Inspect.OwnerProfile", boost::bind(&LLFloaterInspect::onClickOwnerProfile, this));
- mCommitCallbackRegistrar.add("Inspect.CreatorProfile", boost::bind(&LLFloaterInspect::onClickCreatorProfile, this));
- mCommitCallbackRegistrar.add("Inspect.SelectObject", boost::bind(&LLFloaterInspect::onSelectObject, this));
+ mCommitCallbackRegistrar.add("Inspect.OwnerProfile", { boost::bind(&LLFloaterInspect::onClickOwnerProfile, this) });
+ mCommitCallbackRegistrar.add("Inspect.CreatorProfile", { boost::bind(&LLFloaterInspect::onClickCreatorProfile, this) });
+ mCommitCallbackRegistrar.add("Inspect.SelectObject", { boost::bind(&LLFloaterInspect::onSelectObject, this) });
}
bool LLFloaterInspect::postBuild()
@@ -220,7 +220,8 @@ void LLFloaterInspect::refresh()
}
time_t timestamp = (time_t) (obj->mCreationDate/1000000);
- std::string timeStr = getString("timeStamp");
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ std::string timeStr = use_24h ? getString("timeStamp") : getString("timeStampAMPM");
LLSD substitution;
substitution["datetime"] = (S32) timestamp;
LLStringUtil::format (timeStr, substitution);
diff --git a/indra/newview/llfloaterinventorysettings.cpp b/indra/newview/llfloaterinventorysettings.cpp
index e5ee69f240..dd46127d9c 100644
--- a/indra/newview/llfloaterinventorysettings.cpp
+++ b/indra/newview/llfloaterinventorysettings.cpp
@@ -28,9 +28,14 @@
#include "llfloaterinventorysettings.h"
+#include "llcolorswatch.h"
+#include "llviewercontrol.h"
+
LLFloaterInventorySettings::LLFloaterInventorySettings(const LLSD& key)
: LLFloater(key)
{
+ mCommitCallbackRegistrar.add("ScriptPref.applyUIColor", { boost::bind(&LLFloaterInventorySettings::applyUIColor, this, _1, _2) });
+ mCommitCallbackRegistrar.add("ScriptPref.getUIColor", { boost::bind(&LLFloaterInventorySettings::getUIColor, this, _1, _2) });
}
LLFloaterInventorySettings::~LLFloaterInventorySettings()
@@ -38,7 +43,29 @@ LLFloaterInventorySettings::~LLFloaterInventorySettings()
bool LLFloaterInventorySettings::postBuild()
{
+ getChild<LLUICtrl>("favorites_color")->setCommitCallback(boost::bind(&LLFloaterInventorySettings::updateColorSwatch, this));
getChild<LLButton>("ok_btn")->setCommitCallback(boost::bind(&LLFloater::closeFloater, this, false));
+
+ bool enable_color = gSavedSettings.getBOOL("InventoryFavoritesColorText");
+ getChild<LLUICtrl>("favorites_swatch")->setEnabled(enable_color);
+
return true;
}
+void LLFloaterInventorySettings::updateColorSwatch()
+{
+ bool val = getChild<LLUICtrl>("favorites_color")->getValue();
+ getChild<LLUICtrl>("favorites_swatch")->setEnabled(val);
+}
+
+void LLFloaterInventorySettings::applyUIColor(LLUICtrl* ctrl, const LLSD& param)
+{
+ LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue()));
+}
+
+void LLFloaterInventorySettings::getUIColor(LLUICtrl* ctrl, const LLSD& param)
+{
+ LLColorSwatchCtrl* color_swatch = (LLColorSwatchCtrl*)ctrl;
+ color_swatch->setOriginal(LLUIColorTable::instance().getColor(param.asString()));
+}
+
diff --git a/indra/newview/llfloaterinventorysettings.h b/indra/newview/llfloaterinventorysettings.h
index 3fe3a001b9..c27d5d2e1b 100644
--- a/indra/newview/llfloaterinventorysettings.h
+++ b/indra/newview/llfloaterinventorysettings.h
@@ -40,6 +40,11 @@ public:
private:
LLFloaterInventorySettings(const LLSD& key);
~LLFloaterInventorySettings();
+
+ void updateColorSwatch();
+
+ void applyUIColor(LLUICtrl* ctrl, const LLSD& param);
+ void getUIColor(LLUICtrl* ctrl, const LLSD& param);
};
#endif
diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp
index 68b11ec92b..4736e30036 100644
--- a/indra/newview/llfloaterjoystick.cpp
+++ b/indra/newview/llfloaterjoystick.cpp
@@ -44,6 +44,7 @@
#include "llwindow.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
+#include "llgamecontrol.h"
#if LL_WINDOWS && !LL_MESA_HEADLESS
// Require DirectInput version 8
@@ -78,15 +79,22 @@ BOOL CALLBACK di8_list_devices_callback(LPCDIDEVICEINSTANCE device_instance_ptr,
// Capable of detecting devices like Oculus Rift
if (device_instance_ptr && pvRef)
{
+ // We always include the device if it is from 3DConnexion, otherwise
+ // if the GameControl feature is enabled then we perfer to route other devices to it.
std::string product_name = utf16str_to_utf8str(llutf16string(device_instance_ptr->tszProductName));
- S32 size = sizeof(GUID);
- LLSD::Binary data; //just an std::vector
- data.resize(size);
- memcpy(&data[0], &device_instance_ptr->guidInstance /*POD _GUID*/, size);
-
- LLFloaterJoystick * floater = (LLFloaterJoystick*)pvRef;
- LLSD value = data;
- floater->addDevice(product_name, value);
+ bool include_device = LLViewerJoystick::is3DConnexionDevice(product_name) || !LLGameControl::isEnabled();
+
+ if (include_device)
+ {
+ S32 size = sizeof(GUID);
+ LLSD::Binary data; //just an std::vector
+ data.resize(size);
+ memcpy(&data[0], &device_instance_ptr->guidInstance /*POD _GUID*/, size);
+
+ LLFloaterJoystick * floater = (LLFloaterJoystick*)pvRef;
+ LLSD value = data;
+ floater->addDevice(product_name, value);
+ }
}
return DIENUM_CONTINUE;
}
@@ -303,8 +311,13 @@ void LLFloaterJoystick::refreshListOfDevices()
#if LL_WINDOWS && !LL_MESA_HEADLESS
LL_WARNS() << "NDOF connected to device without using SL provided handle" << LL_ENDL;
#endif
- std::string desc = joystick->getDescription();
- if (!desc.empty())
+ // We always include the device if it is from 3DConnexion, otherwise we only
+ // support the device in this context when GameControl feature is disabled.
+ std::string desc = LLViewerJoystick::getInstance()->getDescription();
+ bool include_device = LLViewerJoystick::is3DConnexionDevice(desc) ||
+ (!LLGameControl::isEnabled() && !desc.empty());
+
+ if (include_device)
{
LLSD value = LLSD::Integer(1); // value for selection
addDevice(desc, value);
diff --git a/indra/newview/llfloaterlagmeter.cpp b/indra/newview/llfloaterlagmeter.cpp
index 28fa8dea9a..26d7e3ead2 100644
--- a/indra/newview/llfloaterlagmeter.cpp
+++ b/indra/newview/llfloaterlagmeter.cpp
@@ -47,7 +47,7 @@ const std::string LAG_GOOD_IMAGE_NAME = "lag_status_good.tga";
LLFloaterLagMeter::LLFloaterLagMeter(const LLSD& key)
: LLFloater(key)
{
- mCommitCallbackRegistrar.add("LagMeter.ClickShrink", boost::bind(&LLFloaterLagMeter::onClickShrink, this));
+ mCommitCallbackRegistrar.add("LagMeter.ClickShrink", { boost::bind(&LLFloaterLagMeter::onClickShrink, this) });
}
bool LLFloaterLagMeter::postBuild()
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 52a3e78d04..5c5219bcdd 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -733,7 +733,8 @@ void LLPanelLandGeneral::refresh()
// Display claim date
time_t claim_date = parcel->getClaimDate();
- std::string claim_date_str = getString("time_stamp_template");
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ std::string claim_date_str = use_24h ? getString("time_stamp_template") : getString("time_stamp_template_ampm");
LLSD substitution;
substitution["datetime"] = (S32) claim_date;
LLStringUtil::format (claim_date_str, substitution);
diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp
index c961070787..71dcc3d114 100644
--- a/indra/newview/llfloaterlinkreplace.cpp
+++ b/indra/newview/llfloaterlinkreplace.cpp
@@ -45,7 +45,7 @@ LLFloaterLinkReplace::LLFloaterLinkReplace(const LLSD& key)
mTargetUUID(LLUUID::null),
mBatchSize(gSavedSettings.getU32("LinkReplaceBatchSize"))
{
- mEventTimer.stop();
+ stop();
}
LLFloaterLinkReplace::~LLFloaterLinkReplace()
@@ -202,7 +202,7 @@ void LLFloaterLinkReplace::onStartClickedResponse(const LLSD& notification, cons
mStartBtn->setEnabled(false);
mRefreshBtn->setEnabled(false);
- mEventTimer.start();
+ start();
tick();
}
else
@@ -298,7 +298,7 @@ void LLFloaterLinkReplace::decreaseOpenItemCount()
mStatusText->setText(getString("ReplaceFinished"));
mStartBtn->setEnabled(true);
mRefreshBtn->setEnabled(true);
- mEventTimer.stop();
+ stop();
LL_INFOS() << "Inventory link replace finished." << LL_ENDL;
}
else
@@ -320,7 +320,7 @@ bool LLFloaterLinkReplace::tick()
{
if (!mRemainingInventoryItems.size())
{
- mEventTimer.stop();
+ stop();
break;
}
diff --git a/indra/newview/llfloaterlinkreplace.h b/indra/newview/llfloaterlinkreplace.h
index 7f9f0b59e1..31df083a11 100644
--- a/indra/newview/llfloaterlinkreplace.h
+++ b/indra/newview/llfloaterlinkreplace.h
@@ -86,10 +86,10 @@ public:
LLFloaterLinkReplace(const LLSD& key);
virtual ~LLFloaterLinkReplace();
- bool postBuild();
- virtual void onOpen(const LLSD& key);
+ bool postBuild() override;
+ void onOpen(const LLSD& key) override;
- virtual bool tick();
+ bool tick() override;
private:
void checkEnableStart();
diff --git a/indra/newview/llfloaterluadebug.cpp b/indra/newview/llfloaterluadebug.cpp
new file mode 100644
index 0000000000..362a02a642
--- /dev/null
+++ b/indra/newview/llfloaterluadebug.cpp
@@ -0,0 +1,170 @@
+/**
+ * @file llfloaterluadebug.cpp
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterluadebug.h"
+
+#include "lllineeditor.h"
+#include "lltexteditor.h"
+#include "llviewermenufile.h" // LLFilePickerReplyThread
+
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llfloaterreg.h"
+#include "llfloaterimnearbychat.h"
+
+#include "llluamanager.h"
+#include "llsdutil.h"
+#include "lua_function.h"
+#include "stringize.h"
+#include "tempset.h"
+
+
+LLFloaterLUADebug::LLFloaterLUADebug(const LLSD &key)
+ : LLFloater(key)
+{
+}
+
+
+bool LLFloaterLUADebug::postBuild()
+{
+ mResultOutput = getChild<LLTextEditor>("result_text");
+ mLineInput = getChild<LLLineEditor>("lua_cmd");
+ mScriptPath = getChild<LLLineEditor>("script_path");
+ mOutConnection = LLEventPumps::instance().obtain("lua output")
+ .listen("LLFloaterLUADebug",
+ [mResultOutput=mResultOutput](const LLSD& data)
+ {
+ LLCachedControl<bool> show_source_info(gSavedSettings, "LuaDebugShowSource", false);
+ std::string source_info = show_source_info ? data["source_info"].asString() : "";
+ mResultOutput->pasteTextWithLinebreaks(stringize(data["level"].asString(), source_info, data["msg"].asString()), true);
+ mResultOutput->addLineBreakChar(true);
+ return false;
+ });
+
+ getChild<LLButton>("execute_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this));
+ getChild<LLButton>("browse_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnBrowse, this));
+ getChild<LLButton>("run_btn")->setClickedCallback(boost::bind(&LLFloaterLUADebug::onBtnRun, this));
+ mLineInput->setCommitCallback(boost::bind(&LLFloaterLUADebug::onExecuteClicked, this));
+ mLineInput->setSelectAllonCommit(false);
+
+ return true;
+}
+
+LLFloaterLUADebug::~LLFloaterLUADebug()
+{}
+
+void LLFloaterLUADebug::onExecuteClicked()
+{
+ // Empirically, running Lua code that indirectly invokes the
+ // "LLNotifications" listener can result (via mysterious labyrinthine
+ // viewer UI byways) in a recursive call to this handler. We've seen Bad
+ // Things happen to the viewer with a second call to runScriptLine() with
+ // the same cmd on the same LuaState.
+ if (mExecuting)
+ {
+ LL_DEBUGS("Lua") << "recursive call to onExecuteClicked()" << LL_ENDL;
+ return;
+ }
+ TempSet executing(mExecuting, true);
+ mResultOutput->setValue("");
+
+ std::string cmd = mLineInput->getText();
+ LLLUAmanager::runScriptLine(cmd, [this](int count, const LLSD& result)
+ {
+ completion(count, result);
+ });
+}
+
+void LLFloaterLUADebug::onBtnBrowse()
+{
+ LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterLUADebug::runSelectedScript, this, _1), LLFilePicker::FFLOAD_LUA, false);
+}
+
+void LLFloaterLUADebug::onBtnRun()
+{
+ std::vector<std::string> filenames;
+ std::string filepath = mScriptPath->getText();
+ if (!filepath.empty())
+ {
+ filenames.push_back(filepath);
+ runSelectedScript(filenames);
+ }
+}
+
+void LLFloaterLUADebug::runSelectedScript(const std::vector<std::string> &filenames)
+{
+ if (mExecuting)
+ {
+ LL_DEBUGS("Lua") << "recursive call to runSelectedScript()" << LL_ENDL;
+ return;
+ }
+ TempSet executing(mExecuting, true);
+ mResultOutput->setValue("");
+
+ std::string filepath = filenames[0];
+ if (!filepath.empty())
+ {
+ mScriptPath->setText(filepath);
+ LLLUAmanager::runScriptFile(filepath, false, [this](int count, const LLSD &result)
+ {
+ completion(count, result);
+ });
+ }
+}
+
+void LLFloaterLUADebug::completion(int count, const LLSD& result)
+{
+ if (count < 0)
+ {
+ // error: show error message
+ LLStyle::Params params;
+ params.readonly_color = LLUIColorTable::instance().getColor("LtRed");
+ mResultOutput->appendText(result.asString(), false, params);
+ mResultOutput->endOfDoc();
+ return;
+ }
+ if (count == 0)
+ {
+ // no results
+ mResultOutput->pasteTextWithLinebreaks(stringize("ok ", ++mAck));
+ return;
+ }
+ if (count == 1)
+ {
+ // single result
+ mResultOutput->pasteTextWithLinebreaks(stringize(result));
+ return;
+ }
+ // multiple results
+ const char* sep = "";
+ for (const auto& item : llsd::inArray(result))
+ {
+ mResultOutput->insertText(sep);
+ mResultOutput->pasteTextWithLinebreaks(stringize(item));
+ sep = ", ";
+ }
+}
diff --git a/indra/newview/llfloaterluadebug.h b/indra/newview/llfloaterluadebug.h
new file mode 100644
index 0000000000..e27c63b74d
--- /dev/null
+++ b/indra/newview/llfloaterluadebug.h
@@ -0,0 +1,72 @@
+/**
+ * @file llfloaterluadebug.h
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERLUADEBUG_H
+#define LL_LLFLOATERLUADEBUG_H
+
+#include "llevents.h"
+#include "llfloater.h"
+#include "lua_function.h"
+
+extern "C"
+{
+#include "luau/luacode.h"
+#include "luau/lua.h"
+#include "luau/luaconf.h"
+#include "luau/lualib.h"
+}
+
+class LLLineEditor;
+class LLTextEditor;
+
+class LLFloaterLUADebug :
+ public LLFloater
+{
+ public:
+ LLFloaterLUADebug(const LLSD& key);
+ virtual ~LLFloaterLUADebug();
+
+ /*virtual*/ bool postBuild();
+
+ void onExecuteClicked();
+ void onBtnBrowse();
+ void onBtnRun();
+
+ void runSelectedScript(const std::vector<std::string> &filenames);
+
+private:
+ void completion(int count, const LLSD& result);
+
+ LLTempBoundListener mOutConnection;
+
+ LLTextEditor* mResultOutput;
+ LLLineEditor* mLineInput;
+ LLLineEditor* mScriptPath;
+ U32 mAck{ 0 };
+ bool mExecuting{ false };
+};
+
+#endif // LL_LLFLOATERLUADEBUG_H
+
diff --git a/indra/newview/llfloaterluascripts.cpp b/indra/newview/llfloaterluascripts.cpp
new file mode 100644
index 0000000000..6b3d87543a
--- /dev/null
+++ b/indra/newview/llfloaterluascripts.cpp
@@ -0,0 +1,137 @@
+/**
+ * @file llfloaterluascriptsinfo.cpp
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloaterluascripts.h"
+#include "llevents.h"
+#include <filesystem>
+#include "llluamanager.h"
+#include "llscrolllistctrl.h"
+#include "llviewerwindow.h"
+#include "llwindow.h"
+#include "llviewermenu.h"
+
+const F32 REFRESH_INTERVAL = 1.0f;
+
+LLFloaterLUAScripts::LLFloaterLUAScripts(const LLSD &key)
+ : LLFloater(key),
+ mUpdateTimer(new LLTimer()),
+ mContextMenuHandle()
+{
+ mCommitCallbackRegistrar.add("Script.OpenFolder", {[this](LLUICtrl*, const LLSD &userdata)
+ {
+ if (mScriptList->hasSelectedItem())
+ {
+ std::string target_folder_path = std::filesystem::path((mScriptList->getFirstSelected()->getColumn(1)->getValue().asString())).parent_path().string();
+ gViewerWindow->getWindow()->openFolder(target_folder_path);
+ }
+ }, cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Script.Terminate", {[this](LLUICtrl*, const LLSD &userdata)
+ {
+ std::vector<LLSD> coros = mScriptList->getAllSelectedValues();
+ for (auto coro_name : coros)
+ {
+ LLCoros::instance().killreq(coro_name);
+ }
+ }, cb_info::UNTRUSTED_BLOCK });
+}
+
+
+bool LLFloaterLUAScripts::postBuild()
+{
+ mScriptList = getChild<LLScrollListCtrl>("scripts_list");
+ mScriptList->setRightMouseDownCallback([this](LLUICtrl *ctrl, S32 x, S32 y, MASK mask) { onScrollListRightClicked(ctrl, x, y);});
+
+ LLContextMenu *menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
+ "menu_lua_scripts.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ if (menu)
+ {
+ mContextMenuHandle = menu->getHandle();
+ }
+
+ return true;
+}
+
+LLFloaterLUAScripts::~LLFloaterLUAScripts()
+{
+ auto menu = mContextMenuHandle.get();
+ if (menu)
+ {
+ menu->die();
+ mContextMenuHandle.markDead();
+ }
+}
+
+void LLFloaterLUAScripts::draw()
+{
+ if (mUpdateTimer->checkExpirationAndReset(REFRESH_INTERVAL))
+ {
+ populateScriptList();
+ }
+ LLFloater::draw();
+}
+
+void LLFloaterLUAScripts::populateScriptList()
+{
+ S32 prev_pos = mScriptList->getScrollPos();
+ std::vector<LLSD> prev_selected = mScriptList->getAllSelectedValues();
+ mScriptList->clearRows();
+ mScriptList->updateColumns(true);
+ std::map<std::string, std::string> scripts = LLLUAmanager::getScriptNames();
+ for (auto &it : scripts)
+ {
+ LLSD row;
+ row["value"] = it.first;
+ row["columns"][0]["value"] = std::filesystem::path((it.second)).stem().string();
+ row["columns"][0]["column"] = "script_name";
+ row["columns"][1]["value"] = it.second;
+ row["columns"][1]["column"] = "script_path";
+ mScriptList->addElement(row);
+ }
+ mScriptList->setScrollPos(prev_pos);
+ for (auto value : prev_selected)
+ {
+ mScriptList->setSelectedByValue(value, true);
+ }
+}
+
+void LLFloaterLUAScripts::onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y)
+{
+ LLScrollListItem *item = mScriptList->hitItem(x, y);
+ if (item)
+ {
+ if (!item->getSelected())
+ mScriptList->selectItemAt(x, y, MASK_NONE);
+
+ auto menu = mContextMenuHandle.get();
+ if (menu)
+ {
+ menu->setItemEnabled(std::string("open_folder"), (mScriptList->getNumSelected() == 1));
+ menu->show(x, y);
+ LLMenuGL::showPopup(this, menu, x, y);
+ }
+ }
+}
diff --git a/indra/newview/llfloaterluascripts.h b/indra/newview/llfloaterluascripts.h
new file mode 100644
index 0000000000..14ca42d6fb
--- /dev/null
+++ b/indra/newview/llfloaterluascripts.h
@@ -0,0 +1,54 @@
+/**
+ * @file llfloaterluascriptsinfo.h
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFLOATERLUASCRIPTS_H
+#define LL_LLFLOATERLUASCRIPTS_H
+
+#include "llfloater.h"
+
+class LLScrollListCtrl;
+
+class LLFloaterLUAScripts :
+ public LLFloater
+{
+ public:
+ LLFloaterLUAScripts(const LLSD &key);
+ virtual ~LLFloaterLUAScripts();
+
+ bool postBuild();
+ void draw();
+
+private:
+ void populateScriptList();
+ void onScrollListRightClicked(LLUICtrl *ctrl, S32 x, S32 y);
+
+ std::unique_ptr<LLTimer> mUpdateTimer;
+ LLScrollListCtrl* mScriptList;
+
+ LLHandle<LLContextMenu> mContextMenuHandle;
+};
+
+#endif // LL_LLFLOATERLUASCRIPTS_H
+
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp
index f20fea01c5..e91745fff0 100644
--- a/indra/newview/llfloatermarketplacelistings.cpp
+++ b/indra/newview/llfloatermarketplacelistings.cpp
@@ -58,7 +58,7 @@ LLPanelMarketplaceListings::LLPanelMarketplaceListings()
, mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME)
, mFilterListingFoldersOnly(false)
{
- mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2));
+ mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", { boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2) });
mEnableCallbackRegistrar.add("Marketplace.ViewSort.CheckItem", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemCheck, this, _2));
}
diff --git a/indra/newview/llfloatermemleak.cpp b/indra/newview/llfloatermemleak.cpp
index b4bb45c864..4ec8cbf71d 100644
--- a/indra/newview/llfloatermemleak.cpp
+++ b/indra/newview/llfloatermemleak.cpp
@@ -48,12 +48,12 @@ LLFloaterMemLeak::LLFloaterMemLeak(const LLSD& key)
: LLFloater(key)
{
setTitle("Memory Leaking Simulation Floater");
- mCommitCallbackRegistrar.add("MemLeak.ChangeLeakingSpeed", boost::bind(&LLFloaterMemLeak::onChangeLeakingSpeed, this));
- mCommitCallbackRegistrar.add("MemLeak.ChangeMaxMemLeaking", boost::bind(&LLFloaterMemLeak::onChangeMaxMemLeaking, this));
- mCommitCallbackRegistrar.add("MemLeak.Start", boost::bind(&LLFloaterMemLeak::onClickStart, this));
- mCommitCallbackRegistrar.add("MemLeak.Stop", boost::bind(&LLFloaterMemLeak::onClickStop, this));
- mCommitCallbackRegistrar.add("MemLeak.Release", boost::bind(&LLFloaterMemLeak::onClickRelease, this));
- mCommitCallbackRegistrar.add("MemLeak.Close", boost::bind(&LLFloaterMemLeak::onClickClose, this));
+ mCommitCallbackRegistrar.add("MemLeak.ChangeLeakingSpeed", { boost::bind(&LLFloaterMemLeak::onChangeLeakingSpeed, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("MemLeak.ChangeMaxMemLeaking", { boost::bind(&LLFloaterMemLeak::onChangeMaxMemLeaking, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("MemLeak.Start", { boost::bind(&LLFloaterMemLeak::onClickStart, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("MemLeak.Stop", { boost::bind(&LLFloaterMemLeak::onClickStop, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("MemLeak.Release", { boost::bind(&LLFloaterMemLeak::onClickRelease, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("MemLeak.Close", { boost::bind(&LLFloaterMemLeak::onClickClose, this), cb_info::UNTRUSTED_BLOCK });
}
//----------------------------------------------
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 8332a430e6..b5489d2dd8 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -349,14 +349,14 @@ void LLFloaterModelPreview::initModelPreview()
}
//static
-bool LLFloaterModelPreview::showModelPreview()
+void LLFloaterModelPreview::showModelPreview(const LLUUID& dest_folder)
{
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model");
if (fmp && !fmp->isModelLoading())
{
+ fmp->setUploadDestination(dest_folder);
fmp->loadHighLodModel();
}
- return true;
}
void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl)
@@ -505,7 +505,7 @@ void LLFloaterModelPreview::onClickCalculateBtn()
gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale,
childGetValue("upload_textures").asBoolean(),
upload_skinweights, upload_joint_positions, lock_scale_if_joint_position,
- mUploadModelUrl, false,
+ mUploadModelUrl, mDestinationFolderId, false,
getWholeModelFeeObserverHandle());
toggleCalculateButton(false);
@@ -1660,7 +1660,7 @@ void LLFloaterModelPreview::onUpload(void* user_data)
gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,
mp->childGetValue("upload_textures").asBoolean(),
upload_skinweights, upload_joint_positions, lock_scale_if_joint_position,
- mp->mUploadModelUrl,
+ mp->mUploadModelUrl, mp->mDestinationFolderId,
true, LLHandle<LLWholeModelFeeObserver>(), mp->getWholeModelUploadObserverHandle());
}
@@ -1770,9 +1770,15 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
if (index == LLModelPreview::MESH_OPTIMIZER_AUTO
|| index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
|| index == LLModelPreview::MESH_OPTIMIZER_PRECISE)
- { //rebuild LoD to update triangle counts
+ {
+ // rebuild LoD to update triangle counts
onLODParamCommit(lod, true);
}
+ if (index == LLModelPreview::USE_LOD_ABOVE)
+ {
+ // refresh to pick triangle counts
+ mModelPreview->mDirty = true;
+ }
}
void LLFloaterModelPreview::resetDisplayOptions()
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 6adc084fe8..7b652a3613 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -73,7 +73,8 @@ public:
/*virtual*/ void reshape(S32 width, S32 height, bool called_from_parent = true);
void initModelPreview();
- static bool showModelPreview();
+ void setUploadDestination(const LLUUID& dest_folder) { mDestinationFolderId = dest_folder; }
+ static void showModelPreview(const LLUUID& dest_folder = LLUUID::null);
bool handleMouseDown(S32 x, S32 y, MASK mask);
bool handleMouseUp(S32 x, S32 y, MASK mask);
@@ -164,9 +165,6 @@ protected:
static void onPhysicsBrowse(LLUICtrl* ctrl, void* userdata);
static void onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata);
- static void onPhysicsOptimize(LLUICtrl* ctrl, void* userdata);
- static void onPhysicsDecomposeBack(LLUICtrl* ctrl, void* userdata);
- static void onPhysicsSimplifyBack(LLUICtrl* ctrl, void* userdata);
void draw();
@@ -225,6 +223,7 @@ private:
void createSmoothComboBox(LLComboBox* combo_box, float min, float max);
+ LLUUID mDestinationFolderId;
LLButton* mUploadBtn;
LLButton* mCalculateBtn;
LLViewerTextEditor* mUploadLogText;
diff --git a/indra/newview/llfloatermyenvironment.cpp b/indra/newview/llfloatermyenvironment.cpp
index 891e16a8ef..422f056f01 100644
--- a/indra/newview/llfloatermyenvironment.cpp
+++ b/indra/newview/llfloatermyenvironment.cpp
@@ -38,7 +38,9 @@
#include "llcheckboxctrl.h"
#include "llviewerinventory.h"
#include "llenvironment.h"
+#include "llnotificationsutil.h"
#include "llparcel.h"
+#include "lltrans.h"
#include "llviewerparcelmgr.h"
//=========================================================================
@@ -81,10 +83,10 @@ LLFloaterMyEnvironment::LLFloaterMyEnvironment(const LLSD& key) :
mTypeFilter((0x01 << static_cast<U64>(LLSettingsType::ST_DAYCYCLE)) | (0x01 << static_cast<U64>(LLSettingsType::ST_SKY)) | (0x01 << static_cast<U64>(LLSettingsType::ST_WATER))),
mSelectedAsset()
{
- mCommitCallbackRegistrar.add(ACTION_DOCREATE, [this](LLUICtrl *, const LLSD &userdata) { onDoCreate(userdata); });
- mCommitCallbackRegistrar.add(ACTION_DOEDIT, [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->openSelected(); });
- mCommitCallbackRegistrar.add(ACTION_DOAPPLY, [this](LLUICtrl *, const LLSD &userdata) { onDoApply(userdata.asString()); });
- mCommitCallbackRegistrar.add(ACTION_COPYPASTE, [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->doToSelected(userdata.asString()); });
+ mCommitCallbackRegistrar.add(ACTION_DOCREATE, { [this](LLUICtrl *, const LLSD &userdata) { onDoCreate(userdata); } });
+ mCommitCallbackRegistrar.add(ACTION_DOEDIT, { [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->openSelected(); } });
+ mCommitCallbackRegistrar.add(ACTION_DOAPPLY, { [this](LLUICtrl *, const LLSD &userdata) { onDoApply(userdata.asString()); } });
+ mCommitCallbackRegistrar.add(ACTION_COPYPASTE, { [this](LLUICtrl *, const LLSD &userdata) { mInventoryList->doToSelected(userdata.asString()); } });
mEnableCallbackRegistrar.add(ENABLE_ACTION, [this](LLUICtrl *, const LLSD &userdata) { return canAction(userdata.asString()); });
mEnableCallbackRegistrar.add(ENABLE_CANAPPLY, [this](LLUICtrl *, const LLSD &userdata) { return canApply(userdata.asString()); });
@@ -223,6 +225,35 @@ void LLFloaterMyEnvironment::onFilterEdit(const std::string& search_string)
mInventoryList->setFilterSubString(search_string);
}
+void LLFloaterMyEnvironment::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, uuid_vec_t item_ids)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0)
+ {
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ for (const LLUUID& itemid : item_ids)
+ {
+ LLInventoryItem* inv_item = gInventory.getItem(itemid);
+
+ if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_SETTINGS)
+ {
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
+ update.push_back(new_folder);
+ gInventory.accountForUpdate(update);
+
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
+ new_item->setParent(trash_id);
+ new_item->updateParentOnServer(false);
+ gInventory.updateItem(new_item);
+ }
+ }
+ gInventory.notifyObservers();
+ }
+}
+
void LLFloaterMyEnvironment::onDeleteSelected()
{
uuid_vec_t selected;
@@ -231,27 +262,16 @@ void LLFloaterMyEnvironment::onDeleteSelected()
if (selected.empty())
return;
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- for (const LLUUID& itemid: selected)
- {
- LLInventoryItem* inv_item = gInventory.getItem(itemid);
-
- if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_SETTINGS)
+ LLSD args;
+ args["QUESTION"] = LLTrans::getString(selected.size() > 1 ? "DeleteItems" : "DeleteItem");
+ LLNotificationsUtil::add(
+ "DeleteItems",
+ args,
+ LLSD(),
+ [this, selected](const LLSD& notification, const LLSD& response)
{
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
- update.push_back(new_folder);
- gInventory.accountForUpdate(update);
-
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
- new_item->setParent(trash_id);
- new_item->updateParentOnServer(false);
- gInventory.updateItem(new_item);
- }
- }
- gInventory.notifyObservers();
+ onItemsRemovalConfirmation(notification, response, selected);
+ });
}
@@ -318,13 +338,13 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
if (context == PARAMETER_EDIT)
{
- return (selected.size() == 1) && isSettingSelected(selected.front());
+ return (selected.size() == 1) && isSettingId(selected.front());
}
else if (context == PARAMETER_COPY)
{
for (std::vector<LLUUID>::iterator it = selected.begin(); it != selected.end(); it++)
{
- if(!isSettingSelected(*it))
+ if(!isSettingId(*it))
{
return false;
}
@@ -342,7 +362,7 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
LLClipboard::instance().pasteFromClipboard(ids);
for (std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
{
- if (!isSettingSelected(*it))
+ if (!isSettingId(*it))
{
return false;
}
@@ -351,7 +371,7 @@ bool LLFloaterMyEnvironment::canAction(const std::string &context)
}
else if (context == PARAMETER_COPYUUID)
{
- return (selected.size() == 1) && isSettingSelected(selected.front());
+ return (selected.size() == 1) && isSettingId(selected.front());
}
return false;
@@ -367,16 +387,42 @@ bool LLFloaterMyEnvironment::canApply(const std::string &context)
if (context == PARAMETER_REGION)
{
- return LLEnvironment::instance().canAgentUpdateRegionEnvironment();
+ return isSettingId(selected.front()) && LLEnvironment::instance().canAgentUpdateRegionEnvironment();
}
else if (context == PARAMETER_PARCEL)
{
- return LLEnvironment::instance().canAgentUpdateParcelEnvironment();
+ return isSettingId(selected.front()) && LLEnvironment::instance().canAgentUpdateParcelEnvironment();
}
- else
+ else if (context == PARAMETER_LOCAL)
+ {
+ return isSettingId(selected.front());
+ }
+
+ return false;
+}
+
+bool can_delete(const LLUUID& id)
+{
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if (id == trash_id || gInventory.isObjectDescendentOf(id, trash_id))
+ {
+ return false;
+ }
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(id);
+ if (cat)
+ {
+ if (!get_is_category_removable(&gInventory, id))
+ {
+ return false;
+ }
+ }
+ else if (!get_is_item_removable(&gInventory, id, true))
{
- return (context == PARAMETER_LOCAL);
+ return false;
}
+
+ return true;
}
//-------------------------------------------------------------------------
@@ -389,7 +435,14 @@ void LLFloaterMyEnvironment::refreshButtonStates()
getChild<LLUICtrl>(BUTTON_GEAR)->setEnabled(settings_ok);
getChild<LLUICtrl>(BUTTON_NEWSETTINGS)->setEnabled(true);
- getChild<LLUICtrl>(BUTTON_DELETE)->setEnabled(settings_ok && !selected.empty());
+
+ bool enable_delete = false;
+ if(settings_ok && !selected.empty())
+ {
+ enable_delete = can_delete(selected.front());
+ }
+
+ getChild<LLUICtrl>(BUTTON_DELETE)->setEnabled(enable_delete);
}
//-------------------------------------------------------------------------
@@ -438,7 +491,7 @@ LLUUID LLFloaterMyEnvironment::findItemByAssetId(LLUUID asset_id, bool copyable_
return LLUUID::null;
}
-bool LLFloaterMyEnvironment::isSettingSelected(LLUUID item_id)
+bool LLFloaterMyEnvironment::isSettingId(const LLUUID& item_id)
{
LLInventoryItem* itemp = gInventory.getItem(item_id);
diff --git a/indra/newview/llfloatermyenvironment.h b/indra/newview/llfloatermyenvironment.h
index 8e81b8e5e2..c5d521d207 100644
--- a/indra/newview/llfloatermyenvironment.h
+++ b/indra/newview/llfloatermyenvironment.h
@@ -60,6 +60,7 @@ private:
void onFilterCheckChange();
void onFilterEdit(const std::string& search_string);
void onSelectionChange();
+ void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, uuid_vec_t item_ids);
void onDeleteSelected();
void onDoCreate(const LLSD &data);
void onDoApply(const std::string &context);
@@ -69,7 +70,7 @@ private:
void getSelectedIds(uuid_vec_t& ids) const;
void refreshButtonStates();
- bool isSettingSelected(LLUUID item_id);
+ static bool isSettingId(const LLUUID &item_id);
static LLUUID findItemByAssetId(LLUUID asset_id, bool copyable_only, bool ignore_library);
};
diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp
index 01c50d89c5..569b41cfa9 100644
--- a/indra/newview/llfloaternamedesc.cpp
+++ b/indra/newview/llfloaternamedesc.cpp
@@ -62,11 +62,20 @@ const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
//-----------------------------------------------------------------------------
// LLFloaterNameDesc()
//-----------------------------------------------------------------------------
-LLFloaterNameDesc::LLFloaterNameDesc(const LLSD& filename )
- : LLFloater(filename),
- mIsAudio(false)
+LLFloaterNameDesc::LLFloaterNameDesc(const LLSD& args)
+ : LLFloater(args)
+ , mIsAudio(false)
+ , mIsText(false)
{
- mFilenameAndPath = filename.asString();
+ if (args.isString())
+ {
+ mFilenameAndPath = args.asString();
+ }
+ else
+ {
+ mFilenameAndPath = args["filename"].asString();
+ mDestinationFolderId = args["dest"].asUUID();
+ }
mFilename = gDirUtilp->getBaseFileName(mFilenameAndPath, false);
}
@@ -203,7 +212,8 @@ void LLFloaterNameDesc::onBtnOK( )
LLFloaterPerms::getNextOwnerPerms("Uploads"),
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
- expected_upload_cost));
+ expected_upload_cost,
+ mDestinationFolderId));
upload_new_resource(uploadInfo, callback, nruserdata);
}
@@ -230,8 +240,8 @@ void LLFloaterNameDesc::onBtnCancel()
// LLFloaterSoundPreview()
//-----------------------------------------------------------------------------
-LLFloaterSoundPreview::LLFloaterSoundPreview(const LLSD& filename )
- : LLFloaterNameDesc(filename)
+LLFloaterSoundPreview::LLFloaterSoundPreview(const LLSD& args )
+ : LLFloaterNameDesc(args)
{
mIsAudio = true;
}
@@ -251,8 +261,8 @@ bool LLFloaterSoundPreview::postBuild()
// LLFloaterAnimPreview()
//-----------------------------------------------------------------------------
-LLFloaterAnimPreview::LLFloaterAnimPreview(const LLSD& filename )
- : LLFloaterNameDesc(filename)
+LLFloaterAnimPreview::LLFloaterAnimPreview(const LLSD& args )
+ : LLFloaterNameDesc(args)
{
}
@@ -270,8 +280,8 @@ bool LLFloaterAnimPreview::postBuild()
// LLFloaterScriptPreview()
//-----------------------------------------------------------------------------
-LLFloaterScriptPreview::LLFloaterScriptPreview(const LLSD& filename )
- : LLFloaterNameDesc(filename)
+LLFloaterScriptPreview::LLFloaterScriptPreview(const LLSD& args )
+ : LLFloaterNameDesc(args)
{
mIsText = true;
}
diff --git a/indra/newview/llfloaternamedesc.h b/indra/newview/llfloaternamedesc.h
index aa5571ccc0..a1b9bd3b95 100644
--- a/indra/newview/llfloaternamedesc.h
+++ b/indra/newview/llfloaternamedesc.h
@@ -39,7 +39,7 @@ class LLRadioGroup;
class LLFloaterNameDesc : public LLFloater
{
public:
- LLFloaterNameDesc(const LLSD& filename);
+ LLFloaterNameDesc(const LLSD& args);
virtual ~LLFloaterNameDesc();
bool postBuild() override;
@@ -58,26 +58,27 @@ protected:
std::string mFilenameAndPath;
std::string mFilename;
+ LLUUID mDestinationFolderId;
};
class LLFloaterSoundPreview : public LLFloaterNameDesc
{
public:
- LLFloaterSoundPreview(const LLSD& filename );
+ LLFloaterSoundPreview(const LLSD& args );
bool postBuild() override;
};
class LLFloaterAnimPreview : public LLFloaterNameDesc
{
public:
- LLFloaterAnimPreview(const LLSD& filename );
+ LLFloaterAnimPreview(const LLSD& args );
bool postBuild() override;
};
class LLFloaterScriptPreview : public LLFloaterNameDesc
{
public:
- LLFloaterScriptPreview(const LLSD& filename );
+ LLFloaterScriptPreview(const LLSD& args );
bool postBuild() override;
};
diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp
index a819b30e30..883b285c06 100644
--- a/indra/newview/llfloaternotificationsconsole.cpp
+++ b/indra/newview/llfloaternotificationsconsole.cpp
@@ -151,7 +151,7 @@ bool LLNotificationChannelPanel::update(const LLSD& payload)
LLFloaterNotificationConsole::LLFloaterNotificationConsole(const LLSD& key)
: LLFloater(key)
{
- mCommitCallbackRegistrar.add("ClickAdd", boost::bind(&LLFloaterNotificationConsole::onClickAdd, this));
+ mCommitCallbackRegistrar.add("ClickAdd", { boost::bind(&LLFloaterNotificationConsole::onClickAdd, this) });
}
bool LLFloaterNotificationConsole::postBuild()
diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp
index 26b7304b9a..21aaed14c8 100644
--- a/indra/newview/llfloaterobjectweights.cpp
+++ b/indra/newview/llfloaterobjectweights.cpp
@@ -36,6 +36,14 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
+static const std::string lod_strings[4] =
+{
+ "lowest_lod",
+ "low_lod",
+ "medium_lod",
+ "high_lod",
+};
+
// virtual
bool LLCrossParcelFunctor::apply(LLViewerObject* obj)
{
@@ -75,7 +83,10 @@ LLFloaterObjectWeights::LLFloaterObjectWeights(const LLSD& key)
mSelectedOnLand(NULL),
mRezzedOnLand(NULL),
mRemainingCapacity(NULL),
- mTotalCapacity(NULL)
+ mTotalCapacity(NULL),
+ mLodLevel(nullptr),
+ mTrianglesShown(nullptr),
+ mPixelArea(nullptr)
{
}
@@ -99,6 +110,10 @@ bool LLFloaterObjectWeights::postBuild()
mRemainingCapacity = getChild<LLTextBox>("remaining_capacity");
mTotalCapacity = getChild<LLTextBox>("total_capacity");
+ mLodLevel = getChild<LLTextBox>("lod_level");
+ mTrianglesShown = getChild<LLTextBox>("triangles_shown");
+ mPixelArea = getChild<LLTextBox>("pixel_area");
+
return true;
}
@@ -135,6 +150,69 @@ void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reaso
toggleWeightsLoadingIndicators(false);
}
+void LLFloaterObjectWeights::draw()
+{
+ // Normally it's a bad idea to set text and visibility inside draw
+ // since it can cause rect updates go to different, already drawn elements,
+ // but floater is very simple and these elements are supposed to be isolated
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ if (selection->isEmpty())
+ {
+ const std::string text = getString("nothing_selected");
+ mLodLevel->setText(text);
+ mTrianglesShown->setText(text);
+ mPixelArea->setText(text);
+
+ toggleRenderLoadingIndicators(false);
+ }
+ else
+ {
+ S32 object_lod = -1;
+ bool multiple_lods = false;
+ S32 total_tris = 0;
+ S32 pixel_area = 0;
+ for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin();
+ iter != selection->valid_root_end(); ++iter)
+ {
+ LLViewerObject* object = (*iter)->getObject();
+ S32 lod = object->getLOD();
+ if (object_lod < 0)
+ {
+ object_lod = lod;
+ }
+ else if (object_lod != lod)
+ {
+ multiple_lods = true;
+ }
+
+ if (object->isRootEdit())
+ {
+ total_tris += object->recursiveGetTriangleCount();
+ pixel_area += static_cast<S32>(object->getPixelArea());
+ }
+ }
+
+ if (multiple_lods)
+ {
+ mLodLevel->setText(getString("multiple_lods"));
+ toggleRenderLoadingIndicators(false);
+ }
+ else if (object_lod < 0)
+ {
+ // nodes are waiting for data
+ toggleRenderLoadingIndicators(true);
+ }
+ else
+ {
+ mLodLevel->setText(getString(lod_strings[object_lod]));
+ toggleRenderLoadingIndicators(false);
+ }
+ mTrianglesShown->setText(llformat("%d", total_tris));
+ mPixelArea->setText(llformat("%d", pixel_area));
+ }
+ LLFloater::draw();
+}
+
void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel)
{
if (!parcel || LLSelectMgr::getInstance()->getSelection()->isEmpty())
@@ -252,6 +330,17 @@ void LLFloaterObjectWeights::toggleLandImpactsLoadingIndicators(bool visible)
mTotalCapacity->setVisible(!visible);
}
+void LLFloaterObjectWeights::toggleRenderLoadingIndicators(bool visible)
+{
+ childSetVisible("lod_level_loading_indicator", visible);
+ childSetVisible("triangles_shown_loading_indicator", visible);
+ childSetVisible("pixel_area_loading_indicator", visible);
+
+ mLodLevel->setVisible(!visible);
+ mTrianglesShown->setVisible(!visible);
+ mPixelArea->setVisible(!visible);
+}
+
void LLFloaterObjectWeights::updateIfNothingSelected()
{
const std::string text = getString("nothing_selected");
@@ -269,6 +358,11 @@ void LLFloaterObjectWeights::updateIfNothingSelected()
mRemainingCapacity->setText(text);
mTotalCapacity->setText(text);
+ mLodLevel->setText(text);
+ mTrianglesShown->setText(text);
+ mPixelArea->setText(text);
+
toggleWeightsLoadingIndicators(false);
toggleLandImpactsLoadingIndicators(false);
+ toggleRenderLoadingIndicators(false);
}
diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h
index 3b999f6b9b..bda625564b 100644
--- a/indra/newview/llfloaterobjectweights.h
+++ b/indra/newview/llfloaterobjectweights.h
@@ -58,21 +58,24 @@ public:
LLFloaterObjectWeights(const LLSD& key);
~LLFloaterObjectWeights();
- /*virtual*/ bool postBuild();
+ bool postBuild() override;
- /*virtual*/ void onOpen(const LLSD& key);
+ void onOpen(const LLSD& key) override;
- /*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost);
- /*virtual*/ void setErrorStatus(S32 status, const std::string& reason);
+ void onWeightsUpdate(const SelectionCost& selection_cost) override;
+ void setErrorStatus(S32 status, const std::string& reason) override;
+
+ void draw() override;
void updateLandImpacts(const LLParcel* parcel);
- void refresh();
+ void refresh() override;
private:
- /*virtual*/ void generateTransactionID();
+ void generateTransactionID() override;
void toggleWeightsLoadingIndicators(bool visible);
void toggleLandImpactsLoadingIndicators(bool visible);
+ void toggleRenderLoadingIndicators(bool visible);
void updateIfNothingSelected();
@@ -88,6 +91,10 @@ private:
LLTextBox *mRezzedOnLand;
LLTextBox *mRemainingCapacity;
LLTextBox *mTotalCapacity;
+
+ LLTextBox *mLodLevel;
+ LLTextBox *mTrianglesShown;
+ LLTextBox *mPixelArea;
};
#endif //LL_LLFLOATEROBJECTWEIGHTS_H
diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp
index b06e35f65d..afd77ebd50 100644
--- a/indra/newview/llfloateropenobject.cpp
+++ b/indra/newview/llfloateropenobject.cpp
@@ -55,8 +55,8 @@ LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key)
mPanelInventoryObject(NULL),
mDirty(true)
{
- mCommitCallbackRegistrar.add("OpenObject.MoveToInventory", boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this));
- mCommitCallbackRegistrar.add("OpenObject.Cancel", boost::bind(&LLFloaterOpenObject::onClickCancel, this));
+ mCommitCallbackRegistrar.add("OpenObject.MoveToInventory", { boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("OpenObject.Cancel", { boost::bind(&LLFloaterOpenObject::onClickCancel, this) });
}
LLFloaterOpenObject::~LLFloaterOpenObject()
diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp
index 3eb0c849d3..756d22eea7 100644
--- a/indra/newview/llfloaterperformance.cpp
+++ b/indra/newview/llfloaterperformance.cpp
@@ -67,7 +67,7 @@ protected:
{
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
- registrar.add("Settings.SetRendering", boost::bind(&LLFloaterPerformance::onCustomAction, mFloaterPerformance, _2, mUUIDs.front()));
+ registrar.add("Settings.SetRendering", { boost::bind(&LLFloaterPerformance::onCustomAction, mFloaterPerformance, _2, mUUIDs.front()), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
enable_registrar.add("Settings.IsSelected", boost::bind(&LLFloaterPerformance::isActionChecked, mFloaterPerformance, _2, mUUIDs.front()));
LLContextMenu* menu = createFromFile("menu_avatar_rendering_settings.xml");
diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp
index 7311f0deb6..86a99aba39 100644
--- a/indra/newview/llfloaterperms.cpp
+++ b/indra/newview/llfloaterperms.cpp
@@ -107,9 +107,9 @@ static bool mCapSent = false;
LLFloaterPermsDefault::LLFloaterPermsDefault(const LLSD& seed)
: LLFloater(seed)
{
- mCommitCallbackRegistrar.add("PermsDefault.Copy", boost::bind(&LLFloaterPermsDefault::onCommitCopy, this, _2));
- mCommitCallbackRegistrar.add("PermsDefault.OK", boost::bind(&LLFloaterPermsDefault::onClickOK, this));
- mCommitCallbackRegistrar.add("PermsDefault.Cancel", boost::bind(&LLFloaterPermsDefault::onClickCancel, this));
+ mCommitCallbackRegistrar.add("PermsDefault.Copy", { boost::bind(&LLFloaterPermsDefault::onCommitCopy, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("PermsDefault.OK", { boost::bind(&LLFloaterPermsDefault::onClickOK, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("PermsDefault.Cancel", { boost::bind(&LLFloaterPermsDefault::onClickCancel, this), cb_info::UNTRUSTED_BLOCK });
}
diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp
deleted file mode 100644
index 616c13cdc7..0000000000
--- a/indra/newview/llfloaterpostprocess.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * @file llfloaterpostprocess.cpp
- * @brief LLFloaterPostProcess class definition
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloaterpostprocess.h"
-
-#include "llsliderctrl.h"
-#include "llcheckboxctrl.h"
-#include "llnotificationsutil.h"
-#include "lluictrlfactory.h"
-#include "llviewerdisplay.h"
-#include "llpostprocess.h"
-#include "llcombobox.h"
-#include "lllineeditor.h"
-#include "llviewerwindow.h"
-
-
-LLFloaterPostProcess::LLFloaterPostProcess(const LLSD& key)
- : LLFloater(key)
-{
-}
-
-LLFloaterPostProcess::~LLFloaterPostProcess()
-{
-
-
-}
-bool LLFloaterPostProcess::postBuild()
-{
- /// Color Filter Callbacks
- childSetCommitCallback("ColorFilterToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_color_filter");
- //childSetCommitCallback("ColorFilterGamma", &LLFloaterPostProcess::onFloatControlMoved, &(gPostProcess->tweaks.gamma()));
- childSetCommitCallback("ColorFilterBrightness", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness");
- childSetCommitCallback("ColorFilterSaturation", &LLFloaterPostProcess::onFloatControlMoved, (char*)"saturation");
- childSetCommitCallback("ColorFilterContrast", &LLFloaterPostProcess::onFloatControlMoved, (char*)"contrast");
-
- childSetCommitCallback("ColorFilterBaseR", &LLFloaterPostProcess::onColorControlRMoved, (char*)"contrast_base");
- childSetCommitCallback("ColorFilterBaseG", &LLFloaterPostProcess::onColorControlGMoved, (char*)"contrast_base");
- childSetCommitCallback("ColorFilterBaseB", &LLFloaterPostProcess::onColorControlBMoved, (char*)"contrast_base");
- childSetCommitCallback("ColorFilterBaseI", &LLFloaterPostProcess::onColorControlIMoved, (char*)"contrast_base");
-
- /// Night Vision Callbacks
- childSetCommitCallback("NightVisionToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_night_vision");
- childSetCommitCallback("NightVisionBrightMult", &LLFloaterPostProcess::onFloatControlMoved, (char*)"brightness_multiplier");
- childSetCommitCallback("NightVisionNoiseSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_size");
- childSetCommitCallback("NightVisionNoiseStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"noise_strength");
-
- /// Bloom Callbacks
- childSetCommitCallback("BloomToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_bloom");
- childSetCommitCallback("BloomExtract", &LLFloaterPostProcess::onFloatControlMoved, (char*)"extract_low");
- childSetCommitCallback("BloomSize", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_width");
- childSetCommitCallback("BloomStrength", &LLFloaterPostProcess::onFloatControlMoved, (char*)"bloom_strength");
-
- // Effect loading and saving.
- LLComboBox* comboBox = getChild<LLComboBox>("PPEffectsCombo");
- getChild<LLComboBox>("PPLoadEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onLoadEffect, this, comboBox));
- comboBox->setCommitCallback(boost::bind(&LLFloaterPostProcess::onChangeEffectName, this, _1));
-
- LLLineEditor* editBox = getChild<LLLineEditor>("PPEffectNameEditor");
- getChild<LLComboBox>("PPSaveEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onSaveEffect, this, editBox));
-
- syncMenu();
- return true;
-}
-
-// Bool Toggle
-void LLFloaterPostProcess::onBoolToggle(LLUICtrl* ctrl, void* userData)
-{
- char const * boolVariableName = (char const *)userData;
-
- // check the bool
- LLCheckBoxCtrl* cbCtrl = static_cast<LLCheckBoxCtrl*>(ctrl);
- gPostProcess->tweaks[boolVariableName] = cbCtrl->getValue();
-}
-
-// Float Moved
-void LLFloaterPostProcess::onFloatControlMoved(LLUICtrl* ctrl, void* userData)
-{
- char const * floatVariableName = (char const *)userData;
- LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
- gPostProcess->tweaks[floatVariableName] = sldrCtrl->getValue();
-}
-
-// Color Moved
-void LLFloaterPostProcess::onColorControlRMoved(LLUICtrl* ctrl, void* userData)
-{
- char const * floatVariableName = (char const *)userData;
- LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
- gPostProcess->tweaks[floatVariableName][0] = sldrCtrl->getValue();
-}
-
-// Color Moved
-void LLFloaterPostProcess::onColorControlGMoved(LLUICtrl* ctrl, void* userData)
-{
- char const * floatVariableName = (char const *)userData;
- LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
- gPostProcess->tweaks[floatVariableName][1] = sldrCtrl->getValue();
-}
-
-// Color Moved
-void LLFloaterPostProcess::onColorControlBMoved(LLUICtrl* ctrl, void* userData)
-{
- char const * floatVariableName = (char const *)userData;
- LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
- gPostProcess->tweaks[floatVariableName][2] = sldrCtrl->getValue();
-}
-
-// Color Moved
-void LLFloaterPostProcess::onColorControlIMoved(LLUICtrl* ctrl, void* userData)
-{
- char const * floatVariableName = (char const *)userData;
- LLSliderCtrl* sldrCtrl = static_cast<LLSliderCtrl*>(ctrl);
- gPostProcess->tweaks[floatVariableName][3] = sldrCtrl->getValue();
-}
-
-void LLFloaterPostProcess::onLoadEffect(LLComboBox* comboBox)
-{
- LLSD::String effectName(comboBox->getSelectedValue().asString());
-
- gPostProcess->setSelectedEffect(effectName);
-
- syncMenu();
-}
-
-void LLFloaterPostProcess::onSaveEffect(LLLineEditor* editBox)
-{
- std::string effectName(editBox->getValue().asString());
-
- if (gPostProcess->mAllEffects.has(effectName))
- {
- LLSD payload;
- payload["effect_name"] = effectName;
- LLNotificationsUtil::add("PPSaveEffectAlert", LLSD(), payload, boost::bind(&LLFloaterPostProcess::saveAlertCallback, this, _1, _2));
- }
- else
- {
- gPostProcess->saveEffect(effectName);
- syncMenu();
- }
-}
-
-void LLFloaterPostProcess::onChangeEffectName(LLUICtrl* ctrl)
-{
- // get the combo box and name
- LLLineEditor* editBox = getChild<LLLineEditor>("PPEffectNameEditor");
-
- // set the parameter's new name
- editBox->setValue(ctrl->getValue());
-}
-
-bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-
- // if they choose save, do it. Otherwise, don't do anything
- if (option == 0)
- {
- gPostProcess->saveEffect(notification["payload"]["effect_name"].asString());
-
- syncMenu();
- }
- return false;
-}
-
-void LLFloaterPostProcess::syncMenu()
-{
- // add the combo boxe contents
- LLComboBox* comboBox = getChild<LLComboBox>("PPEffectsCombo");
-
- comboBox->removeall();
-
- LLSD::map_const_iterator currEffect;
- for(currEffect = gPostProcess->mAllEffects.beginMap();
- currEffect != gPostProcess->mAllEffects.endMap();
- ++currEffect)
- {
- comboBox->add(currEffect->first);
- }
-
- // set the current effect as selected.
- comboBox->selectByValue(gPostProcess->getSelectedEffect());
-
- /// Sync Color Filter Menu
- getChild<LLUICtrl>("ColorFilterToggle")->setValue(gPostProcess->tweaks.useColorFilter());
- //getChild<LLUICtrl>("ColorFilterGamma")->setValue(gPostProcess->tweaks.gamma());
- getChild<LLUICtrl>("ColorFilterBrightness")->setValue(gPostProcess->tweaks.brightness());
- getChild<LLUICtrl>("ColorFilterSaturation")->setValue(gPostProcess->tweaks.saturation());
- getChild<LLUICtrl>("ColorFilterContrast")->setValue(gPostProcess->tweaks.contrast());
- getChild<LLUICtrl>("ColorFilterBaseR")->setValue(gPostProcess->tweaks.contrastBaseR());
- getChild<LLUICtrl>("ColorFilterBaseG")->setValue(gPostProcess->tweaks.contrastBaseG());
- getChild<LLUICtrl>("ColorFilterBaseB")->setValue(gPostProcess->tweaks.contrastBaseB());
- getChild<LLUICtrl>("ColorFilterBaseI")->setValue(gPostProcess->tweaks.contrastBaseIntensity());
-
- /// Sync Night Vision Menu
- getChild<LLUICtrl>("NightVisionToggle")->setValue(gPostProcess->tweaks.useNightVisionShader());
- getChild<LLUICtrl>("NightVisionBrightMult")->setValue(gPostProcess->tweaks.brightMult());
- getChild<LLUICtrl>("NightVisionNoiseSize")->setValue(gPostProcess->tweaks.noiseSize());
- getChild<LLUICtrl>("NightVisionNoiseStrength")->setValue(gPostProcess->tweaks.noiseStrength());
-
- /// Sync Bloom Menu
- getChild<LLUICtrl>("BloomToggle")->setValue(LLSD(gPostProcess->tweaks.useBloomShader()));
- getChild<LLUICtrl>("BloomExtract")->setValue(gPostProcess->tweaks.extractLow());
- getChild<LLUICtrl>("BloomSize")->setValue(gPostProcess->tweaks.bloomWidth());
- getChild<LLUICtrl>("BloomStrength")->setValue(gPostProcess->tweaks.bloomStrength());
-}
diff --git a/indra/newview/llfloaterpostprocess.h b/indra/newview/llfloaterpostprocess.h
deleted file mode 100644
index 50b48d8410..0000000000
--- a/indra/newview/llfloaterpostprocess.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @file llfloaterpostprocess.h
- * @brief LLFloaterPostProcess class definition
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLFLOATERPOSTPROCESS_H
-#define LL_LLFLOATERPOSTPROCESS_H
-
-#include "llfloater.h"
-
-class LLButton;
-class LLComboBox;
-class LLLineEditor;
-class LLSliderCtrl;
-class LLTabContainer;
-class LLPanelPermissions;
-class LLPanelObject;
-class LLPanelVolume;
-class LLPanelContents;
-class LLPanelFace;
-
-/**
- * Menu for adjusting the post process settings of the world
- */
-class LLFloaterPostProcess : public LLFloater
-{
-public:
-
- LLFloaterPostProcess(const LLSD& key);
- virtual ~LLFloaterPostProcess();
- bool postBuild();
-
- /// post process callbacks
- static void onBoolToggle(LLUICtrl* ctrl, void* userData);
- static void onFloatControlMoved(LLUICtrl* ctrl, void* userData);
- static void onColorControlRMoved(LLUICtrl* ctrl, void* userData);
- static void onColorControlGMoved(LLUICtrl* ctrl, void* userData);
- static void onColorControlBMoved(LLUICtrl* ctrl, void* userData);
- static void onColorControlIMoved(LLUICtrl* ctrl, void* userData);
- void onLoadEffect(LLComboBox* comboBox);
- void onSaveEffect(LLLineEditor* editBox);
- void onChangeEffectName(LLUICtrl* ctrl);
-
- /// prompts a user when overwriting an effect
- bool saveAlertCallback(const LLSD& notification, const LLSD& response);
-
- /// sync up sliders
- void syncMenu();
-};
-
-#endif
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ce1072a968..2bfe7aabc9 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -54,6 +54,7 @@
#include "llfloaterperformance.h"
#include "llfloatersidepanelcontainer.h"
#include "llfloaterimsession.h"
+#include "llgamecontrol.h"
#include "llkeyboard.h"
#include "llmodaldialog.h"
#include "llnavigationbar.h"
@@ -312,44 +313,44 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
registered_dialog = true;
}
- mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this, _2));
- mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this, _2));
-
- mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this));
- mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this));
- mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this));
- mCommitCallbackRegistrar.add("Pref.ResetCache", boost::bind(&LLFloaterPreference::onClickResetCache, this));
- mCommitCallbackRegistrar.add("Pref.ClickSkin", boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2));
- mCommitCallbackRegistrar.add("Pref.SelectSkin", boost::bind(&LLFloaterPreference::onSelectSkin, this));
- mCommitCallbackRegistrar.add("Pref.SetSounds", boost::bind(&LLFloaterPreference::onClickSetSounds, this));
- mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
- mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this));
- mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this));
- mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this));
- mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this));
- mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this));
- mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this));
- mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreference::updateMaxNonImpostors, this));
- mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this));
- mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreference::onRenderOptionEnable, this));
- mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this));
- mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::refreshUI,this));
- mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2));
- mCommitCallbackRegistrar.add("Pref.applyUIColor", boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2));
- mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2));
- mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this));
- mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this));
- mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this));
- mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this));
- mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this));
- mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this));
- mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this));
- mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this));
- mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this));
+ mCommitCallbackRegistrar.add("Pref.Cancel", { boost::bind(&LLFloaterPreference::onBtnCancel, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.OK", { boost::bind(&LLFloaterPreference::onBtnOK, this, _2), cb_info::UNTRUSTED_BLOCK });
+
+ mCommitCallbackRegistrar.add("Pref.ClearCache", { boost::bind(&LLFloaterPreference::onClickClearCache, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.WebClearCache", { boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.SetCache", { boost::bind(&LLFloaterPreference::onClickSetCache, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.ResetCache", { boost::bind(&LLFloaterPreference::onClickResetCache, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.ClickSkin", { boost::bind(&LLFloaterPreference::onClickSkin, this,_1, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.SelectSkin", { boost::bind(&LLFloaterPreference::onSelectSkin, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.SetSounds", { boost::bind(&LLFloaterPreference::onClickSetSounds, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", { boost::bind(&LLFloaterPreference::onClickEnablePopup, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", { boost::bind(&LLFloaterPreference::onClickDisablePopup, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.LogPath", { boost::bind(&LLFloaterPreference::onClickLogPath, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.RenderExceptions", { boost::bind(&LLFloaterPreference::onClickRenderExceptions, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.AutoAdjustments", { boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.HardwareDefaults", { boost::bind(&LLFloaterPreference::setHardwareDefaults, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", { boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", { boost::bind(&LLFloaterPreference::updateMaxNonImpostors, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", { boost::bind(&LLFloaterPreference::updateMaxComplexity, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", { boost::bind(&LLFloaterPreference::onRenderOptionEnable, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.WindowedMod", { boost::bind(&LLFloaterPreference::onCommitWindowedMode, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.UpdateSliderText", { boost::bind(&LLFloaterPreference::refreshUI,this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.QualityPerformance", { boost::bind(&LLFloaterPreference::onChangeQuality, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.applyUIColor", { boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.getUIColor", { boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.MaturitySettings", { boost::bind(&LLFloaterPreference::onChangeMaturity, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.BlockList", { boost::bind(&LLFloaterPreference::onClickBlockList, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.Proxy", { boost::bind(&LLFloaterPreference::onClickProxySettings, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.TranslationSettings", { boost::bind(&LLFloaterPreference::onClickTranslationSettings, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.AutoReplace", { boost::bind(&LLFloaterPreference::onClickAutoReplace, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.PermsDefault", { boost::bind(&LLFloaterPreference::onClickPermsDefault, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.RememberedUsernames", { boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.SpellChecker", { boost::bind(&LLFloaterPreference::onClickSpellChecker, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.Advanced", { boost::bind(&LLFloaterPreference::onClickAdvanced, this), cb_info::UNTRUSTED_BLOCK });
sSkin = gSavedSettings.getString("SkinCurrent");
- mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this));
+ mCommitCallbackRegistrar.add("Pref.ClickActionChange", { boost::bind(&LLFloaterPreference::onClickActionChange, this), cb_info::UNTRUSTED_BLOCK });
gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2));
gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2));
@@ -363,9 +364,9 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this));
mImpostorsChangedSignal = gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreference::updateIndirectMaxNonImpostors, this, _2));
- mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance()));
- mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this));
- mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering
+ mCommitCallbackRegistrar.add("Pref.ClearLog", { boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance()), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", { boost::bind(&LLFloaterPreference::onDeleteTranscripts, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("UpdateFilter", { boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false), cb_info::UNTRUSTED_BLOCK }); // <FS:ND/> Hook up for filtering
}
void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type )
@@ -401,6 +402,7 @@ void LLFloaterPreference::saveAvatarProperties( void )
}
}
+// static
void LLFloaterPreference::saveAvatarPropertiesCoro(const std::string cap_url, bool allow_publish)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
@@ -438,6 +440,7 @@ bool LLFloaterPreference::postBuild()
mDisabledPopups = getChild<LLScrollListCtrl>("disabled_popups");
mEnablePopupBtn = getChild<LLButton>("enable_this_popup");
mDisablePopupBtn = getChild<LLButton>("disable_this_popup");
+ setPanelVisibility("game_control", LLGameControl::isEnabled());
gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false));
@@ -470,6 +473,8 @@ bool LLFloaterPreference::postBuild()
getChild<LLUICtrl>("log_path_string")->setEnabled(false); // make it read-only but selectable
getChild<LLComboBox>("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this));
+ mTimeFormatCombobox = getChild<LLComboBox>("time_format_combobox");
+ mTimeFormatCombobox->setCommitCallback(boost::bind(&LLFloaterPreference::onTimeFormatChange, this));
getChild<LLComboBox>("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions"));
getChild<LLComboBox>("NonFriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"NonFriendIMOptions"));
@@ -562,21 +567,19 @@ void LLFloaterPreference::draw()
void LLFloaterPreference::saveSettings()
{
LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
- child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
- child_list_t::const_iterator end = tabcontainer->getChildList()->end();
- for ( ; iter != end; ++iter)
+ for (LLView* view : *tabcontainer->getChildList())
{
- LLView* view = *iter;
- LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view);
- if (panel)
+ if (LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view))
+ {
panel->saveSettings();
+ }
}
saveIgnoredNotifications();
}
void LLFloaterPreference::apply()
{
- LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this );
+ LLAvatarPropertiesProcessor::getInstance()->addObserver(gAgent.getID(), this);
LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
if (sSkin != gSavedSettings.getString("SkinCurrent"))
@@ -584,14 +587,14 @@ void LLFloaterPreference::apply()
LLNotificationsUtil::add("ChangeSkin");
refreshSkin(this);
}
+
// Call apply() on all panels that derive from LLPanelPreference
- for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
- iter != tabcontainer->getChildList()->end(); ++iter)
+ for (LLView* view : *tabcontainer->getChildList())
{
- LLView* view = *iter;
- LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view);
- if (panel)
+ if (LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view))
+ {
panel->apply();
+ }
}
gViewerWindow->requestResolutionUpdate(); // for UIScaleFactor
@@ -605,7 +608,7 @@ void LLFloaterPreference::apply()
LLViewerMedia::getInstance()->setCookiesEnabled(getChild<LLUICtrl>("cookies_enabled")->getValue());
- if (hasChild("web_proxy_enabled", true) &&hasChild("web_proxy_editor", true) && hasChild("web_proxy_port", true))
+ if (hasChild("web_proxy_enabled", true) && hasChild("web_proxy_editor", true) && hasChild("web_proxy_port", true))
{
bool proxy_enable = getChild<LLUICtrl>("web_proxy_enabled")->getValue();
std::string proxy_address = getChild<LLUICtrl>("web_proxy_editor")->getValue();
@@ -642,13 +645,12 @@ void LLFloaterPreference::cancel(const std::vector<std::string> settings_to_skip
{
LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
// Call cancel() on all panels that derive from LLPanelPreference
- for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
- iter != tabcontainer->getChildList()->end(); ++iter)
+ for (LLView* view : *tabcontainer->getChildList())
{
- LLView* view = *iter;
- LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view);
- if (panel)
+ if (LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view))
+ {
panel->cancel(settings_to_skip);
+ }
}
// hide joystick pref floater
LLFloaterReg::hideInstance("pref_joystick");
@@ -677,7 +679,7 @@ void LLFloaterPreference::cancel(const std::vector<std::string> settings_to_skip
}
//Need to reload the navmesh if the pathing console is up
LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle();
- if ( !pathfindingConsoleHandle.isDead() )
+ if (!pathfindingConsoleHandle.isDead())
{
LLFloaterPathfindingConsole* pPathfindingConsole = pathfindingConsoleHandle.get();
pPathfindingConsole->onRegionBoundaryCross();
@@ -694,6 +696,15 @@ void LLFloaterPreference::cancel(const std::vector<std::string> settings_to_skip
void LLFloaterPreference::onOpen(const LLSD& key)
{
+ LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
+ for (LLView* view : *tabcontainer->getChildList())
+ {
+ if (LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view))
+ {
+ panel->onOpen(key);
+ }
+ }
+
// this variable and if that follows it are used to properly handle do not disturb mode response message
static bool initialized = false;
// if user is logged in and we haven't initialized do not disturb mode response yet, do it
@@ -761,8 +772,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)
// while preferences floater was closed.
buildPopupLists();
-
- //get the options that were checked
+ // get the options that were checked
onNotificationsChange("FriendIMOptions");
onNotificationsChange("NonFriendIMOptions");
onNotificationsChange("ConferenceIMOptions");
@@ -774,8 +784,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)
refresh();
// Make sure the current state of prefs are saved away when
- // when the floater is opened. That will make cancel do its
- // job
+ // the floater is opened. That will make cancel() do its job
saveSettings();
// Make sure there is a default preference file
@@ -975,9 +984,9 @@ void LLFloaterPreference::onBtnOK(const LLSD& userdata)
}
//Conversation transcript and log path changed so reload conversations based on new location
- if(mPriorInstantMessageLogPath.length())
+ if (mPriorInstantMessageLogPath.length())
{
- if(moveTranscriptsAndLog())
+ if (moveTranscriptsAndLog())
{
//When floaters are empty but have a chat history files, reload chat history into them
LLFloaterIMSessionTab::reloadEmptyFloaters();
@@ -994,11 +1003,14 @@ void LLFloaterPreference::onBtnOK(const LLSD& userdata)
LLUIColorTable::instance().saveUserSettings();
gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), true);
- //Only save once logged in and loaded per account settings
- if(mGotPersonalInfo)
+ // save current config to settings
+ LLGameControl::saveToSettings();
+
+ // Only save once logged in and loaded per account settings
+ if (mGotPersonalInfo)
{
gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), true);
- }
+ }
}
else
{
@@ -1039,28 +1051,38 @@ void LLFloaterPreference::onBtnCancel(const LLSD& userdata)
cancel();
closeFloater();
}
+
+ // restore config from settings
+ LLGameControl::loadFromSettings();
+}
+
+//static
+void LLFloaterPreference::refreshInstance()
+{
+ if (LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"))
+ {
+ instance->refresh();
+ }
}
// static
void LLFloaterPreference::updateUserInfo(const std::string& visibility)
{
- LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
- if (instance)
+ if (LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"))
{
instance->setPersonalInfo(visibility);
}
}
+// static
void LLFloaterPreference::refreshEnabledGraphics()
{
- LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
- if (instance)
+ if (LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"))
{
instance->refresh();
}
- LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced");
- if (advanced)
+ if (LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"))
{
advanced->refresh();
}
@@ -1088,6 +1110,13 @@ void LLFloaterPreference::onLanguageChange()
}
}
+void LLFloaterPreference::onTimeFormatChange()
+{
+ std::string val = mTimeFormatCombobox->getValue();
+ gSavedSettings.setBOOL("Use24HourClock", val == "1");
+ onLanguageChange();
+}
+
void LLFloaterPreference::onNotificationsChange(const std::string& OptionName)
{
mNotificationOptions[OptionName] = getChild<LLComboBox>(OptionName)->getSelectedItemLabel();
@@ -1095,7 +1124,7 @@ void LLFloaterPreference::onNotificationsChange(const std::string& OptionName)
bool show_notifications_alert = true;
for (notifications_map::iterator it_notification = mNotificationOptions.begin(); it_notification != mNotificationOptions.end(); it_notification++)
{
- if(it_notification->second != "No action")
+ if (it_notification->second != "No action")
{
show_notifications_alert = false;
break;
@@ -1107,8 +1136,7 @@ void LLFloaterPreference::onNotificationsChange(const std::string& OptionName)
void LLFloaterPreference::onNameTagOpacityChange(const LLSD& newvalue)
{
- LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("background");
- if (color_swatch)
+ if (LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("background"))
{
LLColor4 new_color = color_swatch->get();
color_swatch->set(new_color.setAlpha((F32)newvalue.asReal()));
@@ -1289,7 +1317,17 @@ void LLAvatarComplexityControls::setIndirectMaxArc()
void LLFloaterPreference::refresh()
{
- LLPanel::refresh();
+ setPanelVisibility("game_control", LLGameControl::isEnabled());
+ LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
+ for (LLView* view : *tabcontainer->getChildList())
+ {
+ if (LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view))
+ {
+ panel->refresh();
+ break;
+ }
+ }
+ LLFloater::refresh();
setMaxNonImpostorsText(
gSavedSettings.getU32("RenderAvatarMaxNonImpostors"),
getChild<LLTextBox>("IndirectMaxNonImpostorsText", true));
@@ -1297,12 +1335,13 @@ void LLFloaterPreference::refresh()
gSavedSettings.getU32("RenderAvatarMaxComplexity"),
getChild<LLTextBox>("IndirectMaxComplexityText", true));
refreshEnabledState();
- LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced");
- if (advanced)
+ if (LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"))
{
advanced->refresh();
}
updateClickActionViews();
+
+ mTimeFormatCombobox->selectByValue(gSavedSettings.getBOOL("Use24HourClock") ? "1" : "0");
}
void LLFloaterPreference::onCommitWindowedMode()
@@ -1312,7 +1351,7 @@ void LLFloaterPreference::onCommitWindowedMode()
void LLFloaterPreference::onChangeQuality(const LLSD& data)
{
- U32 level = (U32)(data.asReal());
+ U32 level = (U32)data.asReal();
LLFeatureManager::getInstance()->setGraphicsLevel(level, true);
refreshEnabledGraphics();
refresh();
@@ -1392,7 +1431,6 @@ void LLFloaterPreference::onClickLogPath()
std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
mPriorInstantMessageLogPath.clear();
-
(new LLDirPickerThread(boost::bind(&LLFloaterPreference::changeLogPath, this, _1, _2), proposed_name))->getFile();
}
@@ -1417,10 +1455,10 @@ bool LLFloaterPreference::moveTranscriptsAndLog()
bool madeDirectory = false;
//Does the directory really exist, if not then make it
- if(!LLFile::isdir(chatLogPath))
+ if (!LLFile::isdir(chatLogPath))
{
//mkdir success is defined as zero
- if(LLFile::mkdir(chatLogPath) != 0)
+ if (LLFile::mkdir(chatLogPath) != 0)
{
return false;
}
@@ -1430,10 +1468,10 @@ bool LLFloaterPreference::moveTranscriptsAndLog()
std::string originalConversationLogDir = LLConversationLog::instance().getFileName();
std::string targetConversationLogDir = gDirUtilp->add(chatLogPath, "conversation.log");
//Try to move the conversation log
- if(!LLConversationLog::instance().moveLog(originalConversationLogDir, targetConversationLogDir))
+ if (!LLConversationLog::instance().moveLog(originalConversationLogDir, targetConversationLogDir))
{
//Couldn't move the log and created a new directory so remove the new directory
- if(madeDirectory)
+ if (madeDirectory)
{
LLFile::rmdir(chatLogPath);
}
@@ -1446,7 +1484,7 @@ bool LLFloaterPreference::moveTranscriptsAndLog()
LLLogChat::getListOfTranscriptFiles(listOfTranscripts);
- if(!LLLogChat::moveTranscripts(gDirUtilp->getChatLogsDir(),
+ if (!LLLogChat::moveTranscripts(gDirUtilp->getChatLogsDir(),
instantMessageLogPath,
listOfTranscripts,
listOfFilesMoved))
@@ -1459,7 +1497,7 @@ bool LLFloaterPreference::moveTranscriptsAndLog()
//Move the conversation log back
LLConversationLog::instance().moveLog(targetConversationLogDir, originalConversationLogDir);
- if(madeDirectory)
+ if (madeDirectory)
{
LLFile::rmdir(chatLogPath);
}
@@ -1506,7 +1544,6 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility)
getChild<LLUICtrl>("voice_call_friends_only_check")->setValue(gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly"));
}
-
void LLFloaterPreference::refreshUI()
{
refresh();
@@ -1790,8 +1827,7 @@ void LLFloaterPreference::onClickActionChange()
void LLFloaterPreference::onAtmosShaderChange()
{
- LLCheckBoxCtrl* ctrl_alm = getChild<LLCheckBoxCtrl>("UseLightShaders");
- if(ctrl_alm)
+ if (LLCheckBoxCtrl* ctrl_alm = getChild<LLCheckBoxCtrl>("UseLightShaders"))
{
//Deferred/SSAO/Shadows
bool bumpshiny = LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump");
@@ -1852,12 +1888,9 @@ void LLFloaterPreference::updateClickActionControls()
// In such case we won't need to do this 'dynamic_cast' nightmare.
// updateTable() can also be avoided
LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
- for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
- iter != tabcontainer->getChildList()->end(); ++iter)
+ for (LLView* view : *tabcontainer->getChildList())
{
- LLView* view = *iter;
- LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
- if (panel)
+ if (LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view))
{
panel->setKeyBind("walk_to",
EMouseClickType::CLICK_LEFT,
@@ -1891,12 +1924,9 @@ void LLFloaterPreference::updateClickActionViews()
// Todo: This is a very ugly way to get access to keybindings.
// Reconsider possible options.
LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");
- for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin();
- iter != tabcontainer->getChildList()->end(); ++iter)
+ for (LLView* view : *tabcontainer->getChildList())
{
- LLView* view = *iter;
- LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view);
- if (panel)
+ if (LLPanelPreferenceControls* panel = dynamic_cast<LLPanelPreferenceControls*>(view))
{
click_to_walk = panel->canKeyBindHandle("walk_to",
EMouseClickType::CLICK_LEFT,
@@ -1952,6 +1982,16 @@ void LLFloaterPreference::selectPanel(const LLSD& name)
}
}
+void LLFloaterPreference::setPanelVisibility(const LLSD& name, bool visible)
+{
+ LLTabContainer * tab_containerp = getChild<LLTabContainer>("pref core");
+ LLPanel * panel = tab_containerp->getPanelByName(name.asStringRef());
+ if (NULL != panel)
+ {
+ tab_containerp->setTabVisibility(panel, visible);
+ }
+}
+
void LLFloaterPreference::selectPrivacyPanel()
{
selectPanel("im");
@@ -1964,11 +2004,24 @@ void LLFloaterPreference::selectChatPanel()
void LLFloaterPreference::changed()
{
- getChild<LLButton>("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0);
+ if (LLConversationLog::instance().getIsLoggingEnabled())
+ {
+ getChild<LLButton>("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0);
+ }
+ else
+ {
+ // onClearLog clears list, then notifies changed() and only then clears file,
+ // so check presence of conversations before checking file, file will cleared later.
+ llstat st;
+ bool has_logs = LLConversationLog::instance().getConversations().size() > 0
+ && LLFile::stat(LLConversationLog::instance().getFileName(), &st) == 0
+ && S_ISREG(st.st_mode)
+ && st.st_size > 0;
+ getChild<LLButton>("clear_log")->setEnabled(has_logs);
+ }
// set 'enable' property for 'Delete transcripts...' button
updateDeleteTranscriptsButton();
-
}
void LLFloaterPreference::saveGraphicsPreset(std::string& preset)
@@ -1995,7 +2048,7 @@ public:
:LLEventTimer(period),
mCallback(cb)
{
- mEventTimer.stop();
+ stop();
}
virtual ~Updater(){}
@@ -2003,15 +2056,15 @@ public:
void update(const LLSD& new_value)
{
mNewValue = new_value;
- mEventTimer.start();
+ start();
}
protected:
- bool tick()
+ bool tick() override
{
mCallback(mNewValue);
- mEventTimer.stop();
+ stop();
return false;
}
@@ -2027,11 +2080,11 @@ LLPanelPreference::LLPanelPreference()
: LLPanel(),
mBandWidthUpdater(NULL)
{
- mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2));
- mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1));
- mCommitCallbackRegistrar.add("Pref.PrefDelete", boost::bind(&LLPanelPreference::deletePreset, this, _2));
- mCommitCallbackRegistrar.add("Pref.PrefSave", boost::bind(&LLPanelPreference::savePreset, this, _2));
- mCommitCallbackRegistrar.add("Pref.PrefLoad", boost::bind(&LLPanelPreference::loadPreset, this, _2));
+ mCommitCallbackRegistrar.add("Pref.setControlFalse", { boost::bind(&LLPanelPreference::setControlFalse,this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.updateMediaAutoPlayCheckbox", { boost::bind(&LLPanelPreference::updateMediaAutoPlayCheckbox, this, _1), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.PrefDelete", { boost::bind(&LLPanelPreference::deletePreset, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.PrefSave", { boost::bind(&LLPanelPreference::savePreset, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.PrefLoad", { boost::bind(&LLPanelPreference::loadPreset, this, _2), cb_info::UNTRUSTED_BLOCK });
}
//virtual
@@ -2076,7 +2129,6 @@ bool LLPanelPreference::postBuild()
if (hasChild("media_enabled", true))
{
bool media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia");
-
getChild<LLCheckBoxCtrl>("media_enabled")->set(media_enabled);
getChild<LLCheckBoxCtrl>("autoplay_enabled")->setEnabled(media_enabled);
}
@@ -2133,41 +2185,41 @@ LLPanelPreference::~LLPanelPreference()
delete mBandWidthUpdater;
}
}
+
+// virtual
void LLPanelPreference::apply()
{
// no-op
}
+// virtual
void LLPanelPreference::saveSettings()
{
- LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced");
-
// Save the value of all controls in the hierarchy
mSavedValues.clear();
std::list<LLView*> view_stack;
view_stack.push_back(this);
- if (advanced)
+ // Search for 'Advanced' panel and add it if found
+ if (LLFloater* advanced = LLFloaterReg::findTypedInstance<LLFloater>("prefs_graphics_advanced"))
{
view_stack.push_back(advanced);
}
- while(!view_stack.empty())
+
+ while (!view_stack.empty())
{
// Process view on top of the stack
LLView* curview = view_stack.front();
view_stack.pop_front();
- LLColorSwatchCtrl* color_swatch = dynamic_cast<LLColorSwatchCtrl *>(curview);
- if (color_swatch)
+ if (LLColorSwatchCtrl* color_swatch = dynamic_cast<LLColorSwatchCtrl*>(curview))
{
mSavedColors[color_swatch->getName()] = color_swatch->get();
}
else
{
- LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview);
- if (ctrl)
+ if (LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview))
{
- LLControlVariable* control = ctrl->getControlVariable();
- if (control)
+ if (LLControlVariable* control = ctrl->getControlVariable())
{
mSavedValues[control] = control->getValue();
}
@@ -2175,10 +2227,9 @@ void LLPanelPreference::saveSettings()
}
// Push children onto the end of the work stack
- for (child_list_t::const_iterator iter = curview->getChildList()->begin();
- iter != curview->getChildList()->end(); ++iter)
+ for (LLView* view : *curview->getChildList())
{
- view_stack.push_back(*iter);
+ view_stack.push_back(view);
}
}
@@ -2320,7 +2371,7 @@ public:
mAccountIndependentSettings.push_back("AutoDisengageMic");
}
- /*virtual*/ void saveSettings()
+ void saveSettings() override
{
LLPanelPreference::saveSettings();
@@ -2335,7 +2386,7 @@ public:
if (find(mAccountIndependentSettings.begin(),
mAccountIndependentSettings.end(), setting) == mAccountIndependentSettings.end())
{
- mSavedValues.erase(it++);
+ it = mSavedValues.erase(it);
}
else
{
@@ -2499,9 +2550,11 @@ void LLPanelPreferenceGraphics::cancel(const std::vector<std::string> settings_t
{
LLPanelPreference::cancel(settings_to_skip);
}
+
void LLPanelPreferenceGraphics::saveSettings()
{
resetDirtyChilds();
+
std::string preset_graphic_active = gSavedSettings.getString("PresetGraphicActive");
if (preset_graphic_active.empty())
{
@@ -2512,8 +2565,10 @@ void LLPanelPreferenceGraphics::saveSettings()
instance->saveGraphicsPreset(preset_graphic_active);
}
}
+
LLPanelPreference::saveSettings();
}
+
void LLPanelPreferenceGraphics::setHardwareDefaults()
{
resetDirtyChilds();
@@ -2538,6 +2593,12 @@ LLPanelPreferenceControls::~LLPanelPreferenceControls()
{
}
+void LLPanelPreferenceControls::refresh()
+{
+ populateControlTable();
+ LLPanelPreference::refresh();
+}
+
bool LLPanelPreferenceControls::postBuild()
{
// populate list of controls
@@ -2609,12 +2670,9 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
cell_params.column = "";
cell_params.value = "";
-
- for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator row_it = contents.rows.begin();
- row_it != contents.rows.end();
- ++row_it)
+ for (LLScrollListItem::Params& row_params : contents.rows)
{
- std::string control = row_it->value.getValue().asString();
+ std::string control = row_params.value.getValue().asString();
if (!control.empty() && control != "menu_separator")
{
bool show = true;
@@ -2633,7 +2691,7 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
if (show)
{
// At the moment viewer is hardcoded to assume that columns are named as lst_ctrl%d
- LLScrollListItem::Params item_params(*row_it);
+ LLScrollListItem::Params item_params(row_params);
item_params.enabled.setValue(enabled);
S32 num_columns = pControlsTable->getNumColumns();
@@ -2658,7 +2716,7 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename)
// value = "menu_separator"
// column = "lst_action" / >
//</rows>
- pControlsTable->addRow(*row_it, EAddPosition::ADD_BOTTOM);
+ pControlsTable->addRow(row_params, EAddPosition::ADD_BOTTOM);
}
}
return true;
@@ -2718,6 +2776,11 @@ void LLPanelPreferenceControls::populateControlTable()
addControlTableRows("control_table_contents_movement.xml");
addControlTableSeparator();
addControlTableRows("control_table_contents_media.xml");
+ addControlTableSeparator();
+ if (LLGameControl::isEnabled())
+ {
+ addControlTableRows("control_table_contents_game_control.xml");
+ }
}
// MODE_THIRD_PERSON; MODE_EDIT_AVATAR; MODE_SITTING
else if (mEditingMode < LLKeyConflictHandler::MODE_SAVED_SETTINGS)
@@ -2734,6 +2797,12 @@ void LLPanelPreferenceControls::populateControlTable()
addControlTableSeparator();
addControlTableRows("control_table_contents_media.xml");
+ addControlTableSeparator();
+
+ if (LLGameControl::isEnabled())
+ {
+ addControlTableRows("control_table_contents_game_control.xml");
+ }
}
else
{
@@ -3109,6 +3178,7 @@ void LLPanelPreferenceControls::onDefaultKeyBind(bool all_modes)
mConflictHandler[mEditingMode].saveToSettings(true);
}
}
+
updateTable();
if (mEditingMode == LLKeyConflictHandler::MODE_THIRD_PERSON || all_modes)
@@ -3127,13 +3197,930 @@ void LLPanelPreferenceControls::onCancelKeyBind()
pControlsTable->deselectAllItems();
}
+//------------------------LLPanelPreferenceGameControl--------------------------------
+
+// LLPanelPreferenceGameControl is effectively a singleton, so we track its instance
+static LLPanelPreferenceGameControl* gGameControlPanel { nullptr };
+static LLScrollListCtrl* gSelectedGrid { nullptr };
+static LLScrollListItem* gSelectedItem { nullptr };
+static LLScrollListCell* gSelectedCell { nullptr };
+
+// static
+void LLPanelPreferenceGameControl::updateDeviceList()
+{
+ if (gGameControlPanel)
+ {
+ gGameControlPanel->updateDeviceListInternal();
+ }
+}
+
+LLPanelPreferenceGameControl::LLPanelPreferenceGameControl()
+{
+ gGameControlPanel = this;
+}
+
+LLPanelPreferenceGameControl::~LLPanelPreferenceGameControl()
+{
+ gGameControlPanel = nullptr;
+}
+
+static LLPanelInjector<LLPanelPreferenceGameControl> t_pref_game_control("panel_preference_game_control");
+
+// Collect all UI control values into mSavedValues
+void LLPanelPreferenceGameControl::saveSettings()
+{
+ LLPanelPreference::saveSettings();
+
+ std::vector<LLScrollListItem*> items = mActionTable->getAllData();
+
+ // Find the channel visually associated with the specified action
+ LLGameControl::getChannel_t getChannel =
+ [&](const std::string& action) -> LLGameControl::InputChannel
+ {
+ for (LLScrollListItem* item : items)
+ {
+ if (action == item->getValue() && (item->getNumColumns() >= 2))
+ {
+ return LLGameControl::getChannelByName(item->getColumn(1)->getValue());
+ }
+ }
+ return LLGameControl::InputChannel();
+ };
+
+ // Use string formatting functions provided by class LLGameControl:
+ if (LLControlVariable* analogMappings = gSavedSettings.getControl("AnalogChannelMappings"))
+ {
+ analogMappings->set(LLGameControl::stringifyAnalogMappings(getChannel));
+ mSavedValues[analogMappings] = analogMappings->getValue();
+ }
+
+ if (LLControlVariable* binaryMappings = gSavedSettings.getControl("BinaryChannelMappings"))
+ {
+ binaryMappings->set(LLGameControl::stringifyBinaryMappings(getChannel));
+ mSavedValues[binaryMappings] = binaryMappings->getValue();
+ }
+
+ if (LLControlVariable* flycamMappings = gSavedSettings.getControl("FlycamChannelMappings"))
+ {
+ flycamMappings->set(LLGameControl::stringifyFlycamMappings(getChannel));
+ mSavedValues[flycamMappings] = flycamMappings->getValue();
+ }
+
+ if (LLControlVariable* knownControllers = gSavedSettings.getControl("KnownGameControllers"))
+ {
+ LLSD deviceOptions(LLSD::emptyMap());
+ for (auto& pair : mDeviceOptions)
+ {
+ pair.second.settings = pair.second.options.saveToString(pair.second.name);
+ if (!pair.second.settings.empty())
+ {
+ deviceOptions.insert(pair.first, pair.second.settings);
+ }
+ }
+ knownControllers->set(deviceOptions);
+ mSavedValues[knownControllers] = deviceOptions;
+ }
+}
+
+void LLPanelPreferenceGameControl::onGridSelect(LLUICtrl* ctrl)
+{
+ clearSelectionState();
+
+ LLScrollListCtrl* table = dynamic_cast<LLScrollListCtrl*>(ctrl);
+ if (!table || !table->getEnabled())
+ return;
+
+ if (LLScrollListItem* item = table->getFirstSelected())
+ {
+ if (initCombobox(item, table))
+ return;
+
+ table->deselectAllItems();
+ }
+}
+
+bool LLPanelPreferenceGameControl::initCombobox(LLScrollListItem* item, LLScrollListCtrl* grid)
+{
+ if (item->getSelectedCell() != 1)
+ return false;
+
+ LLScrollListText* cell = dynamic_cast<LLScrollListText*>(item->getColumn(1));
+ if (!cell)
+ return false;
+
+ LLComboBox* combobox = nullptr;
+ if (grid == mActionTable)
+ {
+ std::string action = item->getValue();
+ LLGameControl::ActionNameType actionNameType = LLGameControl::getActionNameType(action);
+ combobox =
+ actionNameType == LLGameControl::ACTION_NAME_ANALOG ? mAnalogChannelSelector :
+ actionNameType == LLGameControl::ACTION_NAME_BINARY ? mBinaryChannelSelector :
+ actionNameType == LLGameControl::ACTION_NAME_FLYCAM ? mAnalogChannelSelector :
+ nullptr;
+ }
+ else if (grid == mAxisMappings)
+ {
+ combobox = mAxisSelector;
+ }
+ else if (grid == mButtonMappings)
+ {
+ combobox = mBinaryChannelSelector;
+ }
+ if (!combobox)
+ return false;
+
+ // compute new rect for combobox
+ S32 row_index = grid->getItemIndex(item);
+ fitInRect(combobox, grid, row_index, 1);
+
+ std::string channel_name = "NONE";
+ std::string cell_value = cell->getValue();
+ std::vector<LLScrollListItem*> items = combobox->getAllData();
+ for (const LLScrollListItem* item : items)
+ {
+ if (item->getColumn(0)->getValue().asString() == cell_value)
+ {
+ channel_name = item->getValue().asString();
+ break;
+ }
+ }
+
+ std::string value;
+ LLGameControl::InputChannel channel = LLGameControl::getChannelByName(channel_name);
+ if (!channel.isNone())
+ {
+ std::string channel_name = channel.getLocalName();
+ std::string channel_label = getChannelLabel(channel_name, combobox->getAllData());
+ if (combobox->itemExists(channel_label))
+ {
+ value = channel_name;
+ }
+ }
+ if (value.empty())
+ {
+ // Assign the last element in the dropdown list which is "NONE"
+ value = combobox->getAllData().back()->getValue().asString();
+ }
+
+ combobox->setValue(value);
+ combobox->setVisible(true);
+ combobox->showList();
+
+ gSelectedGrid = grid;
+ gSelectedItem = item;
+ gSelectedCell = cell;
+
+ return true;
+}
+
+void LLPanelPreferenceGameControl::onCommitInputChannel(LLUICtrl* ctrl)
+{
+ if (!gSelectedGrid || !gSelectedItem || !gSelectedCell)
+ return;
+
+ LLComboBox* combobox = dynamic_cast<LLComboBox*>(ctrl);
+ llassert(combobox);
+ if (!combobox)
+ return;
+
+ if (gSelectedGrid == mActionTable)
+ {
+ std::string value = combobox->getValue();
+ std::string label = (value == "NONE") ?
+ LLStringUtil::null : combobox->getSelectedItemLabel();
+ gSelectedCell->setValue(label);
+ }
+ else
+ {
+ S32 chosen_index = combobox->getCurrentIndex();
+ if (chosen_index >= 0)
+ {
+ int row_index = gSelectedGrid->getItemIndex(gSelectedItem);
+ llassert(row_index >= 0);
+ LLGameControl::Options& deviceOptions = getSelectedDeviceOptions();
+ std::vector<U8>& map = gSelectedGrid == mAxisMappings ?
+ deviceOptions.getAxisMap() : deviceOptions.getButtonMap();
+ if (chosen_index >= map.size())
+ {
+ chosen_index = row_index;
+ }
+ std::string label = chosen_index == row_index ?
+ LLStringUtil::null : combobox->getSelectedItemLabel();
+ gSelectedCell->setValue(label);
+ map[row_index] = chosen_index;
+ }
+ }
+ gSelectedGrid->deselectAllItems();
+ clearSelectionState();
+}
+
+bool LLPanelPreferenceGameControl::isWaitingForInputChannel()
+{
+ return gSelectedCell != nullptr;
+}
+
+// static
+void LLPanelPreferenceGameControl::applyGameControlInput()
+{
+ if (!gGameControlPanel || !gSelectedGrid || !gSelectedCell)
+ return;
+
+ LLComboBox* combobox;
+ LLGameControl::InputChannel::Type expectedType;
+ if (gGameControlPanel->mAnalogChannelSelector->getVisible())
+ {
+ combobox = gGameControlPanel->mAnalogChannelSelector;
+ expectedType = LLGameControl::InputChannel::TYPE_AXIS;
+ }
+ else if (gGameControlPanel->mBinaryChannelSelector->getVisible())
+ {
+ combobox = gGameControlPanel->mBinaryChannelSelector;
+ expectedType = LLGameControl::InputChannel::TYPE_BUTTON;
+ }
+ else
+ {
+ return;
+ }
+
+ LLGameControl::InputChannel channel = LLGameControl::getActiveInputChannel();
+ if (channel.mType == expectedType)
+ {
+ std::string channel_name = channel.getLocalName();
+ std::string channel_label = LLPanelPreferenceGameControl::getChannelLabel(channel_name, combobox->getAllData());
+ gSelectedCell->setValue(channel_label);
+ gSelectedGrid->deselectAllItems();
+ gGameControlPanel->clearSelectionState();
+ }
+}
+
+void LLPanelPreferenceGameControl::onAxisOptionsSelect()
+{
+ clearSelectionState();
+
+ if (LLScrollListItem* row = mAxisOptions->getFirstSelected())
+ {
+ LLGameControl::Options& options = getSelectedDeviceOptions();
+ S32 row_index = mAxisOptions->getItemIndex(row);
+
+ {
+ // always update invert checkbox value because even though it may have been clicked
+ // the row does not know its cell has been selected
+ constexpr S32 invert_checkbox_column = 1;
+ bool invert = row->getColumn(invert_checkbox_column)->getValue().asBoolean();
+ options.getAxisOptions()[row_index].mMultiplier = invert ? -1 : 1;
+ }
+
+ S32 column_index = row->getSelectedCell();
+ if (column_index == 2 || column_index == 3)
+ {
+ fitInRect(mNumericValueEditor, mAxisOptions, row_index, column_index);
+ if (column_index == 2)
+ {
+ mNumericValueEditor->setMinValue(0);
+ mNumericValueEditor->setMaxValue(LLGameControl::MAX_AXIS_DEAD_ZONE);
+ mNumericValueEditor->setValue(options.getAxisOptions()[row_index].mDeadZone);
+ }
+ else // column_index == 3
+ {
+ mNumericValueEditor->setMinValue(-LLGameControl::MAX_AXIS_OFFSET);
+ mNumericValueEditor->setMaxValue(LLGameControl::MAX_AXIS_OFFSET);
+ mNumericValueEditor->setValue(options.getAxisOptions()[row_index].mOffset);
+ }
+ mNumericValueEditor->setVisible(true);
+ }
+
+ initCombobox(row, mAxisOptions);
+
+ LLGameControl::setDeviceOptions(mSelectedDeviceGUID, options);
+ }
+}
+
+void LLPanelPreferenceGameControl::onCommitNumericValue()
+{
+ if (LLScrollListItem* row = mAxisOptions->getFirstSelected())
+ {
+ LLGameControl::Options& deviceOptions = getSelectedDeviceOptions();
+ S32 value = mNumericValueEditor->getValue().asInteger();
+ S32 row_index = mAxisOptions->getItemIndex(row);
+ S32 column_index = row->getSelectedCell();
+ llassert(column_index == 2 || column_index == 3);
+ if (column_index < 2 || column_index > 3)
+ return;
+
+ if (column_index == 2)
+ {
+ value = std::clamp<S32>(value, 0, LLGameControl::MAX_AXIS_DEAD_ZONE);
+ deviceOptions.getAxisOptions()[row_index].mDeadZone = (U16)value;
+ }
+ else // column_index == 3
+ {
+ value = std::clamp<S32>(value, -LLGameControl::MAX_AXIS_OFFSET, LLGameControl::MAX_AXIS_OFFSET);
+ deviceOptions.getAxisOptions()[row_index].mOffset = (S16)value;
+ }
+ setNumericLabel(row->getColumn(column_index), value);
+ LLGameControl::setDeviceOptions(mSelectedDeviceGUID, deviceOptions);
+ }
+}
+
+bool LLPanelPreferenceGameControl::postBuild()
+{
+ // Above the tab container
+ mCheckGameControlToServer = getChild<LLCheckBoxCtrl>("game_control_to_server");
+ mCheckGameControlToAgent = getChild<LLCheckBoxCtrl>("game_control_to_agent");
+ mCheckAgentToGameControl = getChild<LLCheckBoxCtrl>("agent_to_game_control");
+
+ mCheckGameControlToServer->setCommitCallback([this](LLUICtrl*, const LLSD&)
+ {
+ LLGameControl::setSendToServer(mCheckGameControlToServer->getValue());
+ updateActionTableState();
+ });
+ mCheckGameControlToAgent->setCommitCallback([this](LLUICtrl*, const LLSD&)
+ {
+ LLGameControl::setControlAgent(mCheckGameControlToAgent->getValue());
+ updateActionTableState();
+ });
+ mCheckAgentToGameControl->setCommitCallback([this](LLUICtrl*, const LLSD&)
+ {
+ LLGameControl::setTranslateAgentActions(mCheckAgentToGameControl->getValue());
+ updateActionTableState();
+ });
+
+ getChild<LLTabContainer>("game_control_tabs")->setCommitCallback([this](LLUICtrl*, const LLSD&) { clearSelectionState(); });
+ getChild<LLTabContainer>("device_settings_tabs")->setCommitCallback([this](LLUICtrl*, const LLSD&) { clearSelectionState(); });
+
+ // 1st tab "Channel mappings"
+ mTabChannelMappings = getChild<LLPanel>("tab_channel_mappings");
+ mActionTable = getChild<LLScrollListCtrl>("action_table");
+ mActionTable->setCommitCallback([this](LLUICtrl* ctrl, const LLSD&) { onGridSelect(ctrl); });
+
+ // 2nd tab "Device settings"
+ mTabDeviceSettings = getChild<LLPanel>("tab_device_settings");
+ mNoDeviceMessage = getChild<LLTextBox>("nodevice_message");
+ mDevicePrompt = getChild<LLTextBox>("device_prompt");
+ mSingleDevice = getChild<LLTextBox>("single_device");
+ mDeviceList = getChild<LLComboBox>("device_list");
+ mCheckShowAllDevices = getChild<LLCheckBoxCtrl>("show_all_known_devices");
+ mPanelDeviceSettings = getChild<LLPanel>("device_settings");
+
+ mCheckShowAllDevices->setCommitCallback([this](LLUICtrl*, const LLSD&) { populateDeviceTitle(); });
+ mDeviceList->setCommitCallback([this](LLUICtrl*, const LLSD& value) { populateDeviceSettings(value); });
+
+ mTabAxisOptions = getChild<LLPanel>("tab_axis_options");
+ mAxisOptions = getChild<LLScrollListCtrl>("axis_options");
+ mAxisOptions->setCommitCallback([this](LLUICtrl*, const LLSD&) { onAxisOptionsSelect(); });
+
+ mTabAxisMappings = getChild<LLPanel>("tab_axis_mappings");
+ mAxisMappings = getChild<LLScrollListCtrl>("axis_mappings");
+ mAxisMappings->setCommitCallback([this](LLUICtrl* ctrl, const LLSD&) { onGridSelect(ctrl); });
+
+ mTabButtonMappings = getChild<LLPanel>("tab_button_mappings");
+ mButtonMappings = getChild<LLScrollListCtrl>("button_mappings");
+ mButtonMappings->setCommitCallback([this](LLUICtrl* ctrl, const LLSD&) { onGridSelect(ctrl); });
+
+ mResetToDefaults = getChild<LLButton>("reset_to_defaults");
+ mResetToDefaults->setCommitCallback([this](LLUICtrl* ctrl, const LLSD&) { onResetToDefaults(); });
+
+ // Numeric value editor
+ mNumericValueEditor = getChild<LLSpinCtrl>("numeric_value_editor");
+ mNumericValueEditor->setCommitCallback([this](LLUICtrl*, const LLSD&) { onCommitNumericValue(); });
+
+ // Channel selectors
+ mAnalogChannelSelector = getChild<LLComboBox>("analog_channel_selector");
+ mAnalogChannelSelector->setCommitCallback([this](LLUICtrl* ctrl, const LLSD&) { onCommitInputChannel(ctrl); });
+
+ mBinaryChannelSelector = getChild<LLComboBox>("binary_channel_selector");
+ mBinaryChannelSelector->setCommitCallback([this](LLUICtrl* ctrl, const LLSD&) { onCommitInputChannel(ctrl); });
+
+ mAxisSelector = getChild<LLComboBox>("axis_selector");
+ mAxisSelector->setCommitCallback([this](LLUICtrl* ctrl, const LLSD&) { onCommitInputChannel(ctrl); });
+
+ // Setup the 1st tab
+ populateActionTableRows("game_control_table_rows.xml");
+ addActionTableSeparator();
+ populateActionTableRows("game_control_table_camera_rows.xml");
+
+ // Setup the 2nd tab
+ populateOptionsTableRows();
+ populateMappingTableRows(mAxisMappings, mAxisSelector, LLGameControl::NUM_AXES);
+ populateMappingTableRows(mButtonMappings, mBinaryChannelSelector, LLGameControl::NUM_BUTTONS);
+
+ // Workaround for the common bug:
+ // LLScrollListCtrl with draw_heading="true" initially has incorrect mTop (17 px higher)
+ LLRect rect = mAxisOptions->getRect();
+ rect.mTop = mAxisOptions->getParent()->getRect().getHeight() - 1;
+ mAxisOptions->setRect(rect);
+ mAxisOptions->updateLayout();
+
+ return true;
+}
+
+// Update all UI control values from real objects
+// This function is called before floater is shown
+void LLPanelPreferenceGameControl::onOpen(const LLSD& key)
+{
+ mCheckGameControlToServer->setValue(LLGameControl::getSendToServer());
+ mCheckGameControlToAgent->setValue(LLGameControl::getControlAgent());
+ mCheckAgentToGameControl->setValue(LLGameControl::getTranslateAgentActions());
+
+ clearSelectionState();
+
+ // Setup the 1st tab
+ populateActionTableCells();
+ updateActionTableState();
+
+ updateDeviceListInternal();
+ updateEnable();
+}
+
+void LLPanelPreferenceGameControl::updateDeviceListInternal()
+{
+ // Setup the 2nd tab
+ mDeviceOptions.clear();
+ for (const auto& pair : LLGameControl::getDeviceOptions())
+ {
+ DeviceOptions deviceOptions = { LLStringUtil::null, pair.second, LLGameControl::Options() };
+ deviceOptions.options.loadFromString(deviceOptions.name, deviceOptions.settings);
+ mDeviceOptions.emplace(pair.first, deviceOptions);
+ }
+ // Add missing device settings/options even if they are default
+ for (const auto& device : LLGameControl::getDevices())
+ {
+ if (mDeviceOptions.find(device.getGUID()) == mDeviceOptions.end())
+ {
+ mDeviceOptions[device.getGUID()] = { device.getName(), device.saveOptionsToString(true), device.getOptions() };
+ }
+ }
+ mCheckShowAllDevices->setValue(false);
+ populateDeviceTitle();
+}
+
+void LLPanelPreferenceGameControl::populateActionTableRows(const std::string& filename)
+{
+ LLScrollListCtrl::Contents contents;
+ if (!parseXmlFile(contents, filename, "rows"))
+ return;
+
+ // init basic cell params
+ LLScrollListCell::Params second_cell_params;
+ second_cell_params.font = LLFontGL::getFontSansSerif();
+ second_cell_params.font_halign = LLFontGL::LEFT;
+ second_cell_params.column = mActionTable->getColumn(1)->mName;
+ second_cell_params.value = ""; // Actual value is assigned in populateActionTableCells
+
+ for (const LLScrollListItem::Params& row_params : contents.rows)
+ {
+ std::string name = row_params.value.getValue().asString();
+ if (!name.empty() && name != "menu_separator")
+ {
+ LLScrollListItem::Params new_params(row_params);
+ new_params.enabled.setValue(true);
+ // item_params should already have one column that was defined
+ // in XUI config file, and now we want to add one more
+ if (new_params.columns.size() == 1)
+ {
+ new_params.columns.add(second_cell_params);
+ }
+ mActionTable->addRow(new_params, EAddPosition::ADD_BOTTOM);
+ }
+ else
+ {
+ mActionTable->addRow(row_params, EAddPosition::ADD_BOTTOM);
+ }
+ }
+}
+
+void LLPanelPreferenceGameControl::populateActionTableCells()
+{
+ std::vector<LLScrollListItem*> rows = mActionTable->getAllData();
+ std::vector<LLScrollListItem*> axes = mAnalogChannelSelector->getAllData();
+ std::vector<LLScrollListItem*> btns = mBinaryChannelSelector->getAllData();
+
+ for (LLScrollListItem* row : rows)
+ {
+ if (row->getNumColumns() >= 2) // Skip separators
+ {
+ std::string name = row->getValue().asString();
+ if (!name.empty() && name != "menu_separator")
+ {
+ LLGameControl::InputChannel channel = LLGameControl::getChannelByAction(name);
+ std::string channel_name = channel.getLocalName();
+ std::string channel_label =
+ channel.isAxis() ? getChannelLabel(channel_name, axes) :
+ channel.isButton() ? getChannelLabel(channel_name, btns) :
+ LLStringUtil::null;
+ row->getColumn(1)->setValue(channel_label);
+ }
+ }
+ }
+}
+
+// static
+bool LLPanelPreferenceGameControl::parseXmlFile(LLScrollListCtrl::Contents& contents,
+ const std::string& filename, const std::string& what)
+{
+ LLXMLNodePtr xmlNode;
+ if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode))
+ {
+ LL_WARNS("Preferences") << "Failed to populate " << what << " from '" << filename << "'" << LL_ENDL;
+ return false;
+ }
+
+ LLXUIParser parser;
+ parser.readXUI(xmlNode, contents, filename);
+ if (!contents.validateBlock())
+ {
+ LL_WARNS("Preferences") << "Failed to parse " << what << " from '" << filename << "'" << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
+
+void LLPanelPreferenceGameControl::populateDeviceTitle()
+{
+ mSelectedDeviceGUID.clear();
+
+ bool showAllDevices = mCheckShowAllDevices->getValue().asBoolean();
+ std::size_t deviceCount = showAllDevices ? mDeviceOptions.size() : LLGameControl::getDevices().size();
+
+ mNoDeviceMessage->setVisible(!deviceCount);
+ mDevicePrompt->setVisible(deviceCount);
+ mSingleDevice->setVisible(deviceCount == 1);
+ mDeviceList->setVisible(deviceCount > 1);
+ mPanelDeviceSettings->setVisible(deviceCount);
+
+ auto makeTitle = [](const std::string& guid, const std::string& name) -> std::string
+ {
+ return guid + ", " + name;
+ };
+
+ if (deviceCount == 1)
+ {
+ if (showAllDevices)
+ {
+ const std::pair<std::string, DeviceOptions>& pair = *mDeviceOptions.begin();
+ mSingleDevice->setValue(makeTitle(pair.first, pair.second.name));
+ populateDeviceSettings(pair.first);
+ }
+ else
+ {
+ const LLGameControl::Device& device = LLGameControl::getDevices().front();
+ mSingleDevice->setValue(makeTitle(device.getGUID(), device.getName()));
+ populateDeviceSettings(device.getGUID());
+ }
+ }
+ else if (deviceCount)
+ {
+ mDeviceList->clear();
+ mDeviceList->clearRows();
+
+ auto makeListItem = [](const std::string& guid, const std::string& title)
+ {
+ return LLSD().with("value", guid).with("columns", LLSD().with("label", title));
+ };
+
+ if (showAllDevices)
+ {
+ for (const auto& pair : mDeviceOptions)
+ {
+ mDeviceList->addElement(makeListItem(pair.first, makeTitle(pair.first, pair.second.name)));
+ }
+ }
+ else
+ {
+ for (const LLGameControl::Device& device : LLGameControl::getDevices())
+ {
+ mDeviceList->addElement(makeListItem(device.getGUID(), makeTitle(device.getGUID(), device.getName())));
+ }
+ }
+
+ mDeviceList->selectNthItem(0);
+ populateDeviceSettings(mDeviceList->getValue());
+ }
+}
+
+void LLPanelPreferenceGameControl::populateDeviceSettings(const std::string& guid)
+{
+ LL_INFOS() << "guid: '" << guid << "'" << LL_ENDL;
+
+ mSelectedDeviceGUID = guid;
+ auto options_it = mDeviceOptions.find(guid);
+ llassert_always(options_it != mDeviceOptions.end());
+ const DeviceOptions& deviceOptions = options_it->second;
+
+ populateOptionsTableCells();
+ populateMappingTableCells(mAxisMappings, deviceOptions.options.getAxisMap(), mAxisSelector);
+ populateMappingTableCells(mButtonMappings, deviceOptions.options.getButtonMap(), mBinaryChannelSelector);
+}
+
+void LLPanelPreferenceGameControl::populateOptionsTableRows()
+{
+ mAxisOptions->clearRows();
+
+ std::vector<LLScrollListItem*> items = mAnalogChannelSelector->getAllData();
+
+ LLScrollListItem::Params row_params;
+ LLScrollListCell::Params cell_params;
+ cell_params.font = LLFontGL::getFontMonospace();
+ for (size_t i = 0; i < mAxisOptions->getNumColumns(); ++i)
+ {
+ row_params.columns.add(cell_params);
+ }
+
+ row_params.columns(1).type = "checkbox";
+ row_params.columns(2).font_halign = "right";
+ row_params.columns(3).font_halign = "right";
+
+ for (size_t i = 0; i < LLGameControl::NUM_AXES; ++i)
+ {
+ LLScrollListItem* row = mAxisOptions->addRow(row_params);
+ row->getColumn(0)->setValue(items[i]->getColumn(0)->getValue());
+ }
+}
+
+void LLPanelPreferenceGameControl::populateOptionsTableCells()
+{
+ std::vector<LLScrollListItem*> rows = mAxisOptions->getAllData();
+ const auto& all_axis_options = getSelectedDeviceOptions().getAxisOptions();
+ llassert(rows.size() == all_axis_options.size());
+
+ for (size_t i = 0; i < rows.size(); ++i)
+ {
+ LLScrollListItem* row = rows[i];
+ const LLGameControl::Options::AxisOptions& axis_options = all_axis_options[i];
+ row->getColumn(1)->setValue(axis_options.mMultiplier == -1 ? true : false);
+ setNumericLabel(row->getColumn(2), axis_options.mDeadZone);
+ setNumericLabel(row->getColumn(3), axis_options.mOffset);
+ }
+}
+
+void LLPanelPreferenceGameControl::populateMappingTableRows(LLScrollListCtrl* target,
+ const LLComboBox* source, size_t row_count)
+{
+ target->clearRows();
+
+ std::vector<LLScrollListItem*> items = source->getAllData();
+
+ LLScrollListItem::Params row_params;
+ LLScrollListCell::Params cell_params;
+ cell_params.font = LLFontGL::getFontMonospace();
+ for (size_t i = 0; i < target->getNumColumns(); ++i)
+ {
+ row_params.columns.add(cell_params);
+ }
+
+ for (size_t i = 0; i < row_count; ++i)
+ {
+ LLScrollListItem* row = target->addRow(row_params);
+ row->getColumn(0)->setValue(items[i]->getColumn(0)->getValue());
+ }
+}
+
+void LLPanelPreferenceGameControl::populateMappingTableCells(LLScrollListCtrl* target,
+ const std::vector<U8>& mappings, const LLComboBox* source)
+{
+ std::vector<LLScrollListItem*> rows = target->getAllData();
+ std::vector<LLScrollListItem*> items = source->getAllData();
+ llassert(rows.size() == mappings.size());
+
+ for (size_t i = 0; i < rows.size(); ++i)
+ {
+ U8 mapping = mappings[i];
+ llassert(mapping < items.size());
+ // Default values should look as empty cells
+ rows[i]->getColumn(1)->setValue(mapping == i ? LLSD() :
+ items[mapping]->getColumn(0)->getValue());
+ }
+}
+
+LLGameControl::Options& LLPanelPreferenceGameControl::getSelectedDeviceOptions()
+{
+ auto options_it = mDeviceOptions.find(mSelectedDeviceGUID);
+ llassert_always(options_it != mDeviceOptions.end());
+ return options_it->second.options;
+}
+
+// static
+std::string LLPanelPreferenceGameControl::getChannelLabel(const std::string& channel_name,
+ const std::vector<LLScrollListItem*>& items)
+{
+ if (!channel_name.empty() && channel_name != "NONE")
+ {
+ for (LLScrollListItem* item : items)
+ {
+ if (item->getValue().asString() == channel_name)
+ {
+ if (item->getNumColumns())
+ {
+ return item->getColumn(0)->getValue().asString();
+ }
+ break;
+ }
+ }
+ }
+ return LLStringUtil::null;
+}
+
+// static
+void LLPanelPreferenceGameControl::setNumericLabel(LLScrollListCell* cell, S32 value)
+{
+ // Default values should look as empty cells
+ cell->setValue(value ? llformat("%d ", value) : LLStringUtil::null);
+}
+
+void LLPanelPreferenceGameControl::fitInRect(LLUICtrl* ctrl, LLScrollListCtrl* grid, S32 row_index, S32 col_index)
+{
+ LLRect rect(grid->getCellRect(row_index, col_index));
+ LLView* parent = grid->getParent();
+ while (parent && parent != ctrl->getParent())
+ {
+ rect.translate(parent->getRect().mLeft, parent->getRect().mBottom);
+ parent = parent->getParent();
+ }
+
+ ctrl->setRect(rect);
+ rect.translate(-rect.mLeft, -rect.mBottom);
+ for (LLView* child : *ctrl->getChildList())
+ {
+ LLRect childRect(child->getRect());
+ childRect.intersectWith(rect);
+ if (childRect.mRight < rect.mRight &&
+ childRect.mRight > (rect.mLeft + rect.mRight) / 2)
+ {
+ childRect.mRight = rect.mRight;
+ }
+ child->setRect(childRect);
+ }
+}
+
+void LLPanelPreferenceGameControl::clearSelectionState()
+{
+ gSelectedGrid = nullptr;
+ gSelectedItem = nullptr;
+ gSelectedCell = nullptr;
+ mNumericValueEditor->setVisible(false);
+ mAnalogChannelSelector->setVisible(false);
+ mBinaryChannelSelector->setVisible(false);
+ mAxisSelector->setVisible(false);
+}
+
+void LLPanelPreferenceGameControl::addActionTableSeparator()
+{
+ LLScrollListItem::Params separator_params;
+ separator_params.enabled(false);
+ LLScrollListCell::Params column_params;
+ column_params.type = "icon";
+ column_params.value = "menu_separator";
+ column_params.column = "action";
+ column_params.color = LLColor4(0.f, 0.f, 0.f, 0.7f);
+ column_params.font_halign = LLFontGL::HCENTER;
+ separator_params.columns.add(column_params);
+ mActionTable->addRow(separator_params, EAddPosition::ADD_BOTTOM);
+}
+
+void LLPanelPreferenceGameControl::updateEnable()
+{
+ bool enabled = LLGameControl::isEnabled();
+ LLGameControl::setEnabled(enabled);
+
+ mCheckGameControlToServer->setEnabled(enabled);
+ mCheckGameControlToAgent->setEnabled(enabled);
+ mCheckAgentToGameControl->setEnabled(enabled);
+
+ mActionTable->setEnabled(enabled);
+ mAxisOptions->setEnabled(enabled);
+ mAxisMappings->setEnabled(enabled);
+ mButtonMappings->setEnabled(enabled);
+ mDeviceList->setEnabled(enabled);
+
+ if (!enabled)
+ {
+ //mActionTable->deselectAllItems();
+ mAnalogChannelSelector->setVisible(false);
+ mBinaryChannelSelector->setVisible(false);
+ clearSelectionState();
+ }
+}
+
+void LLPanelPreferenceGameControl::updateActionTableState()
+{
+ // Enable the table if at least one of the GameControl<-->Agent options is enabled
+ bool enable_table = LLGameControl::isEnabled() && (mCheckGameControlToAgent->get() || mCheckAgentToGameControl->get());
+
+ mActionTable->deselectAllItems();
+ mActionTable->setEnabled(enable_table);
+ mAnalogChannelSelector->setVisible(false);
+ mBinaryChannelSelector->setVisible(false);
+}
+
+void LLPanelPreferenceGameControl::onResetToDefaults()
+{
+ clearSelectionState();
+ if (mTabChannelMappings->getVisible())
+ {
+ resetChannelMappingsToDefaults();
+ }
+ else if (mTabDeviceSettings->getVisible() && !mSelectedDeviceGUID.empty())
+ {
+ if (mTabAxisOptions->getVisible())
+ {
+ resetAxisOptionsToDefaults();
+ }
+ else if (mTabAxisMappings->getVisible())
+ {
+ resetAxisMappingsToDefaults();
+ }
+ else if (mTabButtonMappings->getVisible())
+ {
+ resetButtonMappingsToDefaults();
+ }
+ }
+}
+
+void LLPanelPreferenceGameControl::resetChannelMappingsToDefaults()
+{
+ std::vector<std::pair<std::string, LLGameControl::InputChannel>> mappings;
+ LLGameControl::getDefaultMappings(mappings);
+ std::vector<LLScrollListItem*> rows = mActionTable->getAllData();
+ std::vector<LLScrollListItem*> axes = mAnalogChannelSelector->getAllData();
+ std::vector<LLScrollListItem*> btns = mBinaryChannelSelector->getAllData();
+ for (LLScrollListItem* row : rows)
+ {
+ if (row->getNumColumns() >= 2) // Skip separators
+ {
+ std::string action_name = row->getValue().asString();
+ if (!action_name.empty() && action_name != "menu_separator")
+ {
+ std::string channel_label;
+ for (const auto& mapping : mappings)
+ {
+ if (mapping.first == action_name)
+ {
+ std::string channel_name = mapping.second.getLocalName();
+ channel_label =
+ mapping.second.isAxis() ? getChannelLabel(channel_name, axes) :
+ mapping.second.isButton() ? getChannelLabel(channel_name, btns) :
+ LLStringUtil::null;
+ break;
+ }
+ }
+ row->getColumn(1)->setValue(channel_label);
+ }
+ }
+ }
+}
+
+void LLPanelPreferenceGameControl::resetAxisOptionsToDefaults()
+{
+ std::vector<LLScrollListItem*> rows = mAxisOptions->getAllData();
+ llassert(rows.size() == LLGameControl::NUM_AXES);
+ LLGameControl::Options& options = getSelectedDeviceOptions();
+ llassert(options.getAxisOptions().size() == LLGameControl::NUM_AXES);
+ for (U8 i = 0; i < LLGameControl::NUM_AXES; ++i)
+ {
+ rows[i]->getColumn(1)->setValue(false);
+ rows[i]->getColumn(2)->setValue(LLStringUtil::null);
+ rows[i]->getColumn(3)->setValue(LLStringUtil::null);
+ options.getAxisOptions()[i].resetToDefaults();
+ }
+}
+
+void LLPanelPreferenceGameControl::resetAxisMappingsToDefaults()
+{
+ std::vector<LLScrollListItem*> rows = mAxisMappings->getAllData();
+ llassert(rows.size() == LLGameControl::NUM_AXES);
+ LLGameControl::Options& options = getSelectedDeviceOptions();
+ llassert(options.getAxisMap().size() == LLGameControl::NUM_AXES);
+ for (U8 i = 0; i < LLGameControl::NUM_AXES; ++i)
+ {
+ rows[i]->getColumn(1)->setValue(LLStringUtil::null);
+ options.getAxisMap()[i] = i;
+ }
+}
+
+void LLPanelPreferenceGameControl::resetButtonMappingsToDefaults()
+{
+ std::vector<LLScrollListItem*> rows = mButtonMappings->getAllData();
+ llassert(rows.size() == LLGameControl::NUM_BUTTONS);
+ LLGameControl::Options& options = getSelectedDeviceOptions();
+ llassert(options.getButtonMap().size() == LLGameControl::NUM_BUTTONS);
+ for (U8 i = 0; i < LLGameControl::NUM_BUTTONS; ++i)
+ {
+ rows[i]->getColumn(1)->setValue(LLStringUtil::null);
+ options.getButtonMap()[i] = i;
+ }
+}
+
+//------------------------LLFloaterPreferenceProxy--------------------------------
+
LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key)
: LLFloater(key),
mSocksSettingsDirty(false)
{
- mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this));
- mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this));
- mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this));
+ mCommitCallbackRegistrar.add("Proxy.OK", { boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Proxy.Cancel", { boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Proxy.Change", { boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this), cb_info::UNTRUSTED_BLOCK });
}
LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy()
@@ -3170,7 +4157,7 @@ void LLFloaterPreferenceProxy::onOpen(const LLSD& key)
void LLFloaterPreferenceProxy::onClose(bool app_quitting)
{
- if(app_quitting)
+ if (app_quitting)
{
cancel();
}
@@ -3194,7 +4181,7 @@ void LLFloaterPreferenceProxy::saveSettings()
mSavedValues.clear();
std::list<LLView*> view_stack;
view_stack.push_back(this);
- while(!view_stack.empty())
+ while (!view_stack.empty())
{
// Process view on top of the stack
LLView* curview = view_stack.front();
@@ -3281,13 +4268,9 @@ void LLFloaterPreferenceProxy::onClickCloseBtn(bool app_quitting)
void LLFloaterPreferenceProxy::cancel()
{
-
- for (control_values_map_t::iterator iter = mSavedValues.begin();
- iter != mSavedValues.end(); ++iter)
+ for (const auto& iter : mSavedValues)
{
- LLControlVariable* control = iter->first;
- LLSD ctrl_value = iter->second;
- control->set(ctrl_value);
+ iter.first->set(iter.second);
}
mSocksSettingsDirty = false;
closeFloater();
@@ -3312,21 +4295,20 @@ void LLFloaterPreferenceProxy::onChangeSocksSettings()
// Check for invalid states for the other HTTP proxy radio
LLRadioGroup* otherHttpProxy = getChild<LLRadioGroup>("other_http_proxy_type");
if ((otherHttpProxy->getSelectedValue().asString() == "Socks" &&
- !getChild<LLCheckBoxCtrl>("socks_proxy_enabled")->get())||(
+ getChild<LLCheckBoxCtrl>("socks_proxy_enabled")->get() == false )||(
otherHttpProxy->getSelectedValue().asString() == "Web" &&
- !getChild<LLCheckBoxCtrl>("web_proxy_enabled")->get()))
+ getChild<LLCheckBoxCtrl>("web_proxy_enabled")->get() == false ) )
{
otherHttpProxy->selectFirstItem();
}
-
}
void LLFloaterPreference::onUpdateFilterTerm(bool force)
{
- LLWString seachValue = utf8str_to_wstring(mFilterEdit->getValue());
- LLWStringUtil::toLower(seachValue);
+ LLWString seachValue = utf8str_to_wstring( mFilterEdit->getValue() );
+ LLWStringUtil::toLower( seachValue );
- if (!mSearchData || (mSearchData->mLastFilter == seachValue && !force))
+ if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force))
return;
if (mSearchDataDirty)
@@ -3337,7 +4319,7 @@ void LLFloaterPreference::onUpdateFilterTerm(bool force)
mSearchData->mLastFilter = seachValue;
- if (!mSearchData->mRootTab)
+ if( !mSearchData->mRootTab )
return;
mSearchData->mRootTab->hightlightAndHide( seachValue );
@@ -3360,10 +4342,10 @@ void LLFloaterPreference::filterIgnorableNotifications()
void collectChildren( LLView const *aView, ll::prefs::PanelDataPtr aParentPanel, ll::prefs::TabContainerDataPtr aParentTabContainer )
{
- if (!aView)
+ if( !aView )
return;
- llassert_always(aParentPanel || aParentTabContainer);
+ llassert_always( aParentPanel || aParentTabContainer );
for (LLView* pView : *aView->getChildList())
{
@@ -3373,56 +4355,56 @@ void collectChildren( LLView const *aView, ll::prefs::PanelDataPtr aParentPanel,
ll::prefs::PanelDataPtr pCurPanelData = aParentPanel;
ll::prefs::TabContainerDataPtr pCurTabContainer = aParentTabContainer;
- LLPanel const *pPanel = dynamic_cast<LLPanel const*>(pView);
- LLTabContainer const *pTabContainer = dynamic_cast<LLTabContainer const*>(pView);
- ll::ui::SearchableControl const *pSCtrl = dynamic_cast<ll::ui::SearchableControl const*>( pView );
+ LLPanel const *pPanel = dynamic_cast< LLPanel const *>( pView );
+ LLTabContainer const *pTabContainer = dynamic_cast< LLTabContainer const *>( pView );
+ ll::ui::SearchableControl const *pSCtrl = dynamic_cast< ll::ui::SearchableControl const *>( pView );
- if (pTabContainer)
+ if( pTabContainer )
{
pCurPanelData.reset();
- pCurTabContainer = ll::prefs::TabContainerDataPtr(new ll::prefs::TabContainerData);
- pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>(pTabContainer);
+ pCurTabContainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData );
+ pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>( pTabContainer );
pCurTabContainer->mLabel = pTabContainer->getLabel();
pCurTabContainer->mPanel = 0;
- if (aParentPanel)
- aParentPanel->mChildPanel.push_back(pCurTabContainer);
- if (aParentTabContainer)
- aParentTabContainer->mChildPanel.push_back(pCurTabContainer);
+ if( aParentPanel )
+ aParentPanel->mChildPanel.push_back( pCurTabContainer );
+ if( aParentTabContainer )
+ aParentTabContainer->mChildPanel.push_back( pCurTabContainer );
}
- else if (pPanel)
+ else if( pPanel )
{
pCurTabContainer.reset();
- pCurPanelData = ll::prefs::PanelDataPtr(new ll::prefs::PanelData);
+ pCurPanelData = ll::prefs::PanelDataPtr( new ll::prefs::PanelData );
pCurPanelData->mPanel = pPanel;
pCurPanelData->mLabel = pPanel->getLabel();
llassert_always( aParentPanel || aParentTabContainer );
- if (aParentTabContainer)
- aParentTabContainer->mChildPanel.push_back(pCurPanelData);
- else if (aParentPanel)
- aParentPanel->mChildPanel.push_back(pCurPanelData);
+ if( aParentTabContainer )
+ aParentTabContainer->mChildPanel.push_back( pCurPanelData );
+ else if( aParentPanel )
+ aParentPanel->mChildPanel.push_back( pCurPanelData );
}
- else if (pSCtrl && pSCtrl->getSearchText().size())
+ else if( pSCtrl && pSCtrl->getSearchText().size() )
{
- ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr(new ll::prefs::SearchableItem());
+ ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr( new ll::prefs::SearchableItem() );
item->mView = pView;
item->mCtrl = pSCtrl;
- item->mLabel = utf8str_to_wstring(pSCtrl->getSearchText());
- LLWStringUtil::toLower(item->mLabel);
+ item->mLabel = utf8str_to_wstring( pSCtrl->getSearchText() );
+ LLWStringUtil::toLower( item->mLabel );
- llassert_always(aParentPanel || aParentTabContainer);
+ llassert_always( aParentPanel || aParentTabContainer );
- if (aParentPanel)
- aParentPanel->mChildren.push_back(item);
- if (aParentTabContainer)
- aParentTabContainer->mChildren.push_back(item);
+ if( aParentPanel )
+ aParentPanel->mChildren.push_back( item );
+ if( aParentTabContainer )
+ aParentTabContainer->mChildren.push_back( item );
}
- collectChildren(pView, pCurPanelData, pCurTabContainer);
+ collectChildren( pView, pCurPanelData, pCurTabContainer );
}
}
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 40806c22fc..d5bd43e0ab 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -36,9 +36,13 @@
#include "llfloater.h"
#include "llavatarpropertiesprocessor.h"
#include "llconversationlog.h"
+#include "llgamecontrol.h"
+#include "llkeyconflict.h"
+#include "llscrolllistcell.h"
+#include "llscrolllistctrl.h"
#include "llsearcheditor.h"
#include "llsetkeybinddialog.h"
-#include "llkeyconflict.h"
+#include "llspinctrl.h"
class LLConversationLogObserver;
class LLPanelPreference;
@@ -51,6 +55,7 @@ class LLScrollListCell;
class LLSliderCtrl;
class LLSD;
class LLTextBox;
+class LLPanelPreferenceGameControl;
namespace ll
{
@@ -80,12 +85,14 @@ public:
void apply();
void cancel(const std::vector<std::string> settings_to_skip = {});
- /*virtual*/ void draw();
- /*virtual*/ bool postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
- /*virtual*/ void onClose(bool app_quitting);
- /*virtual*/ void changed();
- /*virtual*/ void changed(const LLUUID& session_id, U32 mask) {};
+ virtual void draw() override;
+ virtual bool postBuild() override;
+ virtual void onOpen(const LLSD& key) override;
+ virtual void onClose(bool app_quitting) override;
+ virtual void changed() override;
+ virtual void changed(const LLUUID& session_id, U32 mask) override {};
+
+ static void refreshInstance();
// static data update, called from message handler
static void updateUserInfo(const std::string& visibility);
@@ -99,7 +106,7 @@ public:
// update Show Favorites checkbox
static void updateShowFavoritesCheckbox(bool val);
- void processProperties( void* pData, EAvatarProcessorType type );
+ void processProperties( void* pData, EAvatarProcessorType type ) override;
void saveAvatarProperties( void );
static void saveAvatarPropertiesCoro(const std::string url, bool allow_publish);
void selectPrivacyPanel();
@@ -117,6 +124,7 @@ protected:
void onClickClearCache(); // Clear viewer texture cache, file cache on next startup
void onClickBrowserClearCache(); // Clear web history and caches as well as viewer caches above
void onLanguageChange();
+ void onTimeFormatChange();
void onNotificationsChange(const std::string& OptionName);
void onNameTagOpacityChange(const LLSD& newvalue);
@@ -167,7 +175,7 @@ public:
void setPersonalInfo(const std::string& visibility);
void refreshEnabledState();
void onCommitWindowedMode();
- void refresh(); // Refresh enable/disable
+ void refresh() override; // Refresh enable/disable
// if the quality radio buttons are changed
void onChangeQuality(const LLSD& data);
@@ -196,6 +204,7 @@ public:
void buildPopupLists();
static void refreshSkin(void* data);
void selectPanel(const LLSD& name);
+ void setPanelVisibility(const LLSD& name, bool visible);
void saveGraphicsPreset(std::string& preset);
void setRecommendedSettings();
@@ -234,6 +243,7 @@ private:
LLButton* mDeleteTranscriptsBtn = nullptr;
LLButton* mEnablePopupBtn = nullptr;
LLButton* mDisablePopupBtn = nullptr;
+ LLComboBox* mTimeFormatCombobox = nullptr;
std::unique_ptr< ll::prefs::SearchData > mSearchData;
bool mSearchDataDirty;
@@ -251,7 +261,7 @@ class LLPanelPreference : public LLPanel
{
public:
LLPanelPreference();
- /*virtual*/ bool postBuild();
+ virtual bool postBuild() override;
virtual ~LLPanelPreference();
@@ -297,12 +307,12 @@ private:
class LLPanelPreferenceGraphics : public LLPanelPreference
{
public:
- bool postBuild();
- void draw();
- void cancel(const std::vector<std::string> settings_to_skip = {});
- void saveSettings();
+ bool postBuild() override;
+ void draw() override;
+ void cancel(const std::vector<std::string> settings_to_skip = {}) override;
+ void saveSettings() override;
void resetDirtyChilds();
- void setHardwareDefaults();
+ void setHardwareDefaults() override;
void setPresetText();
protected:
@@ -320,11 +330,13 @@ public:
LLPanelPreferenceControls();
virtual ~LLPanelPreferenceControls();
- bool postBuild();
+ bool postBuild() override;
- void apply();
- void cancel(const std::vector<std::string> settings_to_skip = {});
- void saveSettings();
+ void refresh() override;
+
+ void apply() override;
+ void cancel(const std::vector<std::string> settings_to_skip = {}) override;
+ void saveSettings() override;
void resetDirtyChilds();
void onListCommit();
@@ -340,9 +352,12 @@ public:
void updateAndApply();
// from interface
- /*virtual*/ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes);
- /*virtual*/ void onDefaultKeyBind(bool all_modes);
- /*virtual*/ void onCancelKeyBind();
+ bool onSetKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes) override;
+ void onDefaultKeyBind(bool all_modes) override;
+ void onCancelKeyBind() override;
+
+ // Cleans content and then adds content from xml files according to current mEditingMode
+ void populateControlTable();
private:
// reloads settings, discards current changes, updates table
@@ -353,9 +368,6 @@ private:
bool addControlTableRows(const std::string &filename);
void addControlTableSeparator();
- // Cleans content and then adds content from xml files according to current mEditingMode
- void populateControlTable();
-
// Updates keybindings from storage to table
void updateTable();
@@ -367,6 +379,118 @@ private:
S32 mEditingMode;
};
+class LLPanelPreferenceGameControl : public LLPanelPreference
+{
+ LOG_CLASS(LLPanelPreferenceGameControl);
+public:
+
+ enum InputType
+ {
+ TYPE_AXIS,
+ TYPE_BUTTON,
+ TYPE_NONE
+ };
+
+ static void updateDeviceList();
+
+ LLPanelPreferenceGameControl();
+ ~LLPanelPreferenceGameControl();
+
+ void onOpen(const LLSD& key) override;
+
+ // This function squirrels away the current values of the controls so that
+ // cancel() can restore them.
+ void saveSettings() override;
+
+ void updateDeviceListInternal();
+
+ void onGridSelect(LLUICtrl* ctrl);
+ void onCommitInputChannel(LLUICtrl* ctrl);
+
+ void onAxisOptionsSelect();
+ void onCommitNumericValue();
+
+ static bool isWaitingForInputChannel();
+ static void applyGameControlInput();
+
+protected:
+ bool postBuild() override;
+
+ void populateActionTableRows(const std::string& filename);
+ void populateActionTableCells();
+ static bool parseXmlFile(LLScrollListCtrl::Contents& contents,
+ const std::string& filename, const std::string& what);
+
+ void populateDeviceTitle();
+ void populateDeviceSettings(const std::string& guid);
+ void populateOptionsTableRows();
+ void populateOptionsTableCells();
+ void populateMappingTableRows(LLScrollListCtrl* target,
+ const LLComboBox* source, size_t row_count);
+ void populateMappingTableCells(LLScrollListCtrl* target,
+ const std::vector<U8>& mappings, const LLComboBox* source);
+ LLGameControl::Options& getSelectedDeviceOptions();
+
+ static std::string getChannelLabel(const std::string& channelName,
+ const std::vector<LLScrollListItem*>& items);
+ static void setNumericLabel(LLScrollListCell* cell, S32 value);
+ static void fitInRect(LLUICtrl* ctrl, LLScrollListCtrl* grid, S32 row_index, S32 col_index);
+
+private:
+ bool initCombobox(LLScrollListItem* item, LLScrollListCtrl* grid);
+ void clearSelectionState();
+ void addActionTableSeparator();
+ void updateEnable();
+ void updateActionTableState();
+ void onResetToDefaults();
+ void resetChannelMappingsToDefaults();
+ void resetAxisOptionsToDefaults();
+ void resetAxisMappingsToDefaults();
+ void resetButtonMappingsToDefaults();
+
+ // Above the tab container
+ LLCheckBoxCtrl* mCheckGameControlToServer { nullptr }; // send game_control data to server
+ LLCheckBoxCtrl* mCheckGameControlToAgent { nullptr }; // use game_control data to move avatar
+ LLCheckBoxCtrl* mCheckAgentToGameControl { nullptr }; // translate external avatar actions to game_control data
+
+ // 1st tab "Channel mappings"
+ LLPanel* mTabChannelMappings { nullptr };
+ LLScrollListCtrl* mActionTable { nullptr };
+
+ // 2nd tab "Device settings"
+ LLPanel* mTabDeviceSettings { nullptr };
+ LLTextBox* mNoDeviceMessage { nullptr };
+ LLTextBox* mDevicePrompt { nullptr };
+ LLTextBox* mSingleDevice { nullptr };
+ LLComboBox* mDeviceList { nullptr };
+ LLCheckBoxCtrl* mCheckShowAllDevices { nullptr };
+ LLPanel* mPanelDeviceSettings { nullptr };
+ LLPanel* mTabAxisOptions { nullptr };
+ LLScrollListCtrl* mAxisOptions { nullptr };
+ LLPanel* mTabAxisMappings { nullptr };
+ LLScrollListCtrl* mAxisMappings { nullptr };
+ LLPanel* mTabButtonMappings { nullptr };
+ LLScrollListCtrl* mButtonMappings { nullptr };
+
+ LLButton* mResetToDefaults { nullptr };
+
+ // Numeric value editor
+ LLSpinCtrl* mNumericValueEditor { nullptr };
+
+ // Channel selectors
+ LLComboBox* mAnalogChannelSelector { nullptr };
+ LLComboBox* mBinaryChannelSelector { nullptr };
+ LLComboBox* mAxisSelector { nullptr };
+
+ struct DeviceOptions
+ {
+ std::string name, settings;
+ LLGameControl::Options options;
+ };
+ std::map<std::string, DeviceOptions> mDeviceOptions;
+ std::string mSelectedDeviceGUID;
+};
+
class LLAvatarComplexityControls
{
public:
@@ -391,13 +515,13 @@ public:
void cancel();
protected:
- bool postBuild();
- void onOpen(const LLSD& key);
- void onClose(bool app_quitting);
+ bool postBuild() override;
+ void onOpen(const LLSD& key) override;
+ void onClose(bool app_quitting) override;
void saveSettings();
void onBtnOk();
void onBtnCancel();
- void onClickCloseBtn(bool app_quitting = false);
+ void onClickCloseBtn(bool app_quitting = false) override;
void onChangeSocksSettings();
diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp
index daa3d7e3be..3cccecfa4a 100644
--- a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp
+++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp
@@ -45,12 +45,12 @@
LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key)
: LLFloater(key)
{
- mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this));
- mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this));
- mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this));
+ mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this) });
+ mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this) });
+ mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this) });
- mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2));
- mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2));
+ mCommitCallbackRegistrar.add("Pref.Cancel", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Pref.OK", { boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2), cb_info::UNTRUSTED_BLOCK });
}
LLFloaterPreferenceGraphicsAdvanced::~LLFloaterPreferenceGraphicsAdvanced()
diff --git a/indra/newview/llfloaterpreferenceviewadvanced.cpp b/indra/newview/llfloaterpreferenceviewadvanced.cpp
index 3481397daa..290742a4cd 100644
--- a/indra/newview/llfloaterpreferenceviewadvanced.cpp
+++ b/indra/newview/llfloaterpreferenceviewadvanced.cpp
@@ -37,7 +37,7 @@
LLFloaterPreferenceViewAdvanced::LLFloaterPreferenceViewAdvanced(const LLSD& key)
: LLFloater(key)
{
- mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterPreferenceViewAdvanced::onCommitSettings, this));
+ mCommitCallbackRegistrar.add("CommitSettings", { boost::bind(&LLFloaterPreferenceViewAdvanced::onCommitSettings, this), cb_info::UNTRUSTED_BLOCK });
}
LLFloaterPreferenceViewAdvanced::~LLFloaterPreferenceViewAdvanced()
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 219a9ca520..ac3e942e15 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -148,40 +148,6 @@ public:
static LLSD getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count );
};
-
-/*
-void unpack_request_params(
- LLMessageSystem* msg,
- LLDispatcher::sparam_t& strings,
- LLDispatcher::iparam_t& integers)
-{
- char str_buf[MAX_STRING];
- S32 str_count = msg->getNumberOfBlocksFast(_PREHASH_StringData);
- S32 i;
- for (i = 0; i < str_count; ++i)
- {
- // we treat the SParam as binary data (since it might be an
- // LLUUID in compressed form which may have embedded \0's,)
- str_buf[0] = '\0';
- S32 data_size = msg->getSizeFast(_PREHASH_StringData, i, _PREHASH_SParam);
- if (data_size >= 0)
- {
- msg->getBinaryDataFast(_PREHASH_StringData, _PREHASH_SParam,
- str_buf, data_size, i, MAX_STRING - 1);
- strings.push_back(std::string(str_buf, data_size));
- }
- }
-
- U32 int_buf;
- S32 int_count = msg->getNumberOfBlocksFast(_PREHASH_IntegerData);
- for (i = 0; i < int_count; ++i)
- {
- msg->getU32("IntegerData", "IParam", int_buf, i);
- integers.push_back(int_buf);
- }
-}
-*/
-
class LLPanelRegionEnvironment : public LLPanelEnvironmentInfo
{
public:
@@ -259,8 +225,8 @@ bool LLFloaterRegionInfo::postBuild()
panel = new LLPanelRegionGeneralInfo;
mInfoPanels.push_back(panel);
- panel->getCommitCallbackRegistrar().add("RegionInfo.ManageTelehub", boost::bind(&LLPanelRegionInfo::onClickManageTelehub, panel));
- panel->getCommitCallbackRegistrar().add("RegionInfo.ManageRestart", boost::bind(&LLPanelRegionInfo::onClickManageRestartSchedule, panel));
+ panel->getCommitCallbackRegistrar().add("RegionInfo.ManageTelehub", { boost::bind(&LLPanelRegionInfo::onClickManageTelehub, panel) });
+ panel->getCommitCallbackRegistrar().add("RegionInfo.ManageRestart", { boost::bind(&LLPanelRegionInfo::onClickManageRestartSchedule, panel) });
panel->buildFromFile("panel_region_general.xml");
mTab->addTabPanel(panel);
@@ -326,8 +292,8 @@ void LLFloaterRegionInfo::onOpen(const LLSD& key)
disableTabCtrls();
return;
}
- refreshFromRegion(gAgent.getRegion());
- requestRegionInfo();
+ refreshFromRegion(gAgent.getRegion(), ERefreshFromRegionPhase::BeforeRequestRegionInfo);
+ requestRegionInfo(true);
if (!mGodLevelChangeSlot.connected())
{
@@ -347,12 +313,14 @@ void LLFloaterRegionInfo::onRegionChanged()
{
if (getVisible()) //otherwise onOpen will do request
{
- requestRegionInfo();
+ requestRegionInfo(false);
}
}
-void LLFloaterRegionInfo::requestRegionInfo()
+void LLFloaterRegionInfo::requestRegionInfo(bool is_opening)
{
+ mIsRegionInfoRequestedFromOpening = is_opening;
+
LLTabContainer* tab = findChild<LLTabContainer>("region_panels");
if (tab)
{
@@ -523,8 +491,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
panel->getChild<LLSpinCtrl>("agent_limit_spin")->setMaxValue((F32)hard_agent_limit);
- LLPanelRegionGeneralInfo* panel_general = LLFloaterRegionInfo::getPanelGeneral();
- if (panel)
+ if (LLPanelRegionGeneralInfo* panel_general = LLFloaterRegionInfo::getPanelGeneral())
{
panel_general->setObjBonusFactor(object_bonus_factor);
}
@@ -537,6 +504,18 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
panel->getChildView("access_combo")->setEnabled(gAgent.isGodlike() || (region && region->canManageEstate() && !teen_grid));
panel->setCtrlsEnabled(allow_modify);
+ panel->getChild<LLLineEditor>("estate_id")->setValue((S32)region_info.mEstateID);
+
+ if (region)
+ {
+ panel->getChild<LLLineEditor>("grid_position_x")->setValue((S32)(region->getOriginGlobal()[VX] / 256));
+ panel->getChild<LLLineEditor>("grid_position_y")->setValue((S32)(region->getOriginGlobal()[VY] / 256));
+ }
+ else
+ {
+ panel->getChild<LLLineEditor>("grid_position_x")->setDefaultText();
+ panel->getChild<LLLineEditor>("grid_position_y")->setDefaultText();
+ }
// DEBUG PANEL
panel = tab->getChild<LLPanel>("Debug");
@@ -561,21 +540,25 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
{
// Note: region info also causes LLRegionInfoModel::instance().update(msg); -> requestRegion(); -> changed message
// we need to know env version here and in update(msg) to know when to request and when not to, when to filter 'changed'
- floater->refreshFromRegion(gAgent.getRegion());
+ ERefreshFromRegionPhase phase = floater->mIsRegionInfoRequestedFromOpening ?
+ ERefreshFromRegionPhase::AfterRequestRegionInfo :
+ ERefreshFromRegionPhase::NotFromFloaterOpening;
+ floater->refreshFromRegion(gAgent.getRegion(), phase);
} // else will rerequest on onOpen either way
}
// static
-void LLFloaterRegionInfo::sRefreshFromRegion(LLViewerRegion* region)
+void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region)
{
- if (region != gAgent.getRegion()) { return; }
-
- LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info");
- if (!floater) { return; }
+ if (region != gAgent.getRegion())
+ return;
- if (floater->getVisible() && region == gAgent.getRegion())
+ if (LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info"))
{
- floater->refreshFromRegion(region);
+ if (floater->getVisible() && region == gAgent.getRegion())
+ {
+ floater->refreshFromRegion(region, ERefreshFromRegionPhase::NotFromFloaterOpening);
+ }
}
}
@@ -682,7 +665,7 @@ void LLFloaterRegionInfo::onTabSelected(const LLSD& param)
active_panel->onOpen(LLSD());
}
-void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region)
+void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
if (!region)
{
@@ -692,7 +675,7 @@ void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region)
// call refresh from region on all panels
for (const auto& infoPanel : mInfoPanels)
{
- infoPanel->refreshFromRegion(region);
+ infoPanel->refreshFromRegion(region, phase);
}
mEnvironmentPanel->refreshFromRegion(region);
}
@@ -725,7 +708,7 @@ void LLFloaterRegionInfo::onGodLevelChange(U8 god_level)
LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info");
if (floater && floater->getVisible())
{
- refreshFromRegion(gAgent.getRegion());
+ refreshFromRegion(gAgent.getRegion(), ERefreshFromRegionPhase::NotFromFloaterOpening);
}
}
@@ -795,7 +778,7 @@ void LLPanelRegionInfo::updateChild(LLUICtrl* child_ctr)
}
// virtual
-bool LLPanelRegionInfo::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelRegionInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
if (region) mHost = region->getHost();
return true;
@@ -823,12 +806,10 @@ void LLPanelRegionInfo::sendEstateOwnerMessage(
}
else
{
- strings_t::const_iterator it = strings.begin();
- strings_t::const_iterator end = strings.end();
- for(; it != end; ++it)
+ for (const std::string& string : strings)
{
msg->nextBlock("ParamList");
- msg->addString("Parameter", *it);
+ msg->addString("Parameter", string);
}
}
msg->sendReliable(mHost);
@@ -887,13 +868,16 @@ void LLPanelRegionInfo::onClickManageRestartSchedule()
/////////////////////////////////////////////////////////////////////////////
// LLPanelRegionGeneralInfo
//
-bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
bool allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
setCtrlsEnabled(allow_modify);
getChildView("apply_btn")->setEnabled(false);
getChildView("access_text")->setEnabled(allow_modify);
// getChildView("access_combo")->setEnabled(allow_modify);
+ getChildView("estate_id")->setEnabled(false);
+ getChildView("grid_position_x")->setEnabled(false);
+ getChildView("grid_position_y")->setEnabled(false);
// now set in processRegionInfo for teen grid detection
getChildView("kick_btn")->setEnabled(allow_modify);
getChildView("kick_all_btn")->setEnabled(allow_modify);
@@ -904,7 +888,7 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region)
// Data gets filled in by processRegionInfo
- return LLPanelRegionInfo::refreshFromRegion(region);
+ return LLPanelRegionInfo::refreshFromRegion(region, phase);
}
bool LLPanelRegionGeneralInfo::postBuild()
@@ -1173,7 +1157,7 @@ bool LLPanelRegionDebugInfo::postBuild()
}
// virtual
-bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
bool allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
setCtrlsEnabled(allow_modify);
@@ -1191,7 +1175,7 @@ bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region)
getChildView("cancel_restart_btn")->setEnabled(allow_modify);
getChildView("region_debug_console_btn")->setEnabled(allow_modify);
- return LLPanelRegionInfo::refreshFromRegion(region);
+ return LLPanelRegionInfo::refreshFromRegion(region, phase);
}
// virtual
@@ -1233,7 +1217,7 @@ void LLPanelRegionDebugInfo::callbackAvatarID(const uuid_vec_t& ids, const std::
if (ids.empty() || names.empty()) return;
mTargetAvatar = ids[0];
getChild<LLUICtrl>("target_avatar_name")->setValue(LLSD(names[0].getCompleteName()));
- refreshFromRegion( gAgent.getRegion() );
+ refreshFromRegion(gAgent.getRegion(), ERefreshFromRegionPhase::NotFromFloaterOpening);
}
// static
@@ -1675,7 +1659,7 @@ void LLPanelRegionTerrainInfo::updateForMaterialType()
}
// virtual
-bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
bool owner_or_god = gAgent.isGodlike()
|| (region && (region->getOwner() == gAgent.getID()));
@@ -1819,7 +1803,7 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
getChildView("upload_raw_btn")->setEnabled(owner_or_god);
getChildView("bake_terrain_btn")->setEnabled(owner_or_god);
- return LLPanelRegionInfo::refreshFromRegion(region);
+ return LLPanelRegionInfo::refreshFromRegion(region, phase);
}
@@ -2289,25 +2273,27 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region)
refresh();
}
-bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
updateControls(region);
// let the parent class handle the general data collection.
- bool rv = LLPanelRegionInfo::refreshFromRegion(region);
-
- // We want estate info. To make sure it works across region
- // boundaries and multiple packets, we add a serial number to the
- // integers and track against that on update.
- strings_t strings;
- //integers_t integers;
- //LLFloaterRegionInfo::incrementSerial();
- LLFloaterRegionInfo::nextInvoice();
- LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
- //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate();
+ bool rv = LLPanelRegionInfo::refreshFromRegion(region, phase);
+ if (phase != ERefreshFromRegionPhase::BeforeRequestRegionInfo)
+ {
+ // We want estate info. To make sure it works across region
+ // boundaries and multiple packets, we add a serial number to the
+ // integers and track against that on update.
+ strings_t strings;
+ //integers_t integers;
+ //LLFloaterRegionInfo::incrementSerial();
+ LLFloaterRegionInfo::nextInvoice();
+ LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
+ //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate();
- sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings);
+ sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings);
+ }
refresh();
@@ -2528,7 +2514,7 @@ LLPanelEstateCovenant::LLPanelEstateCovenant()
}
// virtual
-bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
LLTextBox* region_name = getChild<LLTextBox>("region_name_text");
if (region_name)
@@ -2574,13 +2560,17 @@ bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region)
getChild<LLButton>("reset_covenant")->setEnabled(gAgent.isGodlike() || (region && region->canManageEstate()));
// let the parent class handle the general data collection.
- bool rv = LLPanelRegionInfo::refreshFromRegion(region);
- LLMessageSystem *msg = gMessageSystem;
- msg->newMessage("EstateCovenantRequest");
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
- msg->sendReliable(region->getHost());
+ bool rv = LLPanelRegionInfo::refreshFromRegion(region, phase);
+
+ if (phase != ERefreshFromRegionPhase::AfterRequestRegionInfo)
+ {
+ gMessageSystem->newMessage("EstateCovenantRequest");
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gMessageSystem->sendReliable(region->getHost());
+ }
+
return rv;
}
@@ -3128,7 +3118,7 @@ std::string LLPanelRegionExperiences::regionCapabilityQuery(LLViewerRegion* regi
return region->getCapability(cap);
}
-bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
bool allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
@@ -3151,10 +3141,13 @@ bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
mTrusted->loading();
mTrusted->setReadonly(!allow_modify);
- LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1),
- boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1));
+ if (phase != ERefreshFromRegionPhase::AfterRequestRegionInfo)
+ {
+ LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1),
+ boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1));
+ }
- return LLPanelRegionInfo::refreshFromRegion(region);
+ return LLPanelRegionInfo::refreshFromRegion(region, phase);
}
LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel)
@@ -4181,35 +4174,32 @@ void LLPanelEstateAccess::copyListToClipboard(std::string list_name)
{
LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess();
if (!panel) return;
- LLNameListCtrl* name_list = panel->getChild<LLNameListCtrl>(list_name);
- if (!name_list) return;
+ LLNameListCtrl* name_list = panel->getChild<LLNameListCtrl>(list_name);
std::vector<LLScrollListItem*> list_vector = name_list->getAllData();
- if (list_vector.size() == 0) return;
+ if (list_vector.empty())
+ return;
LLSD::String list_to_copy;
- for (std::vector<LLScrollListItem*>::const_iterator iter = list_vector.begin();
- iter != list_vector.end();
- iter++)
+ for (LLScrollListItem* item : list_vector)
{
- LLScrollListItem *item = (*iter);
if (item)
{
+ if (!list_to_copy.empty())
+ {
+ list_to_copy += "\n";
+ }
list_to_copy += item->getColumn(0)->getValue().asString();
}
- if (std::next(iter) != list_vector.end())
- {
- list_to_copy += "\n";
- }
}
LLClipboard::instance().copyToClipboard(utf8str_to_wstring(list_to_copy), 0, static_cast<S32>(list_to_copy.length()));
}
-bool LLPanelEstateAccess::refreshFromRegion(LLViewerRegion* region)
+bool LLPanelEstateAccess::refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase)
{
updateLists();
- return LLPanelRegionInfo::refreshFromRegion(region);
+ return LLPanelRegionInfo::refreshFromRegion(region, phase);
}
//=========================================================================
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index 65c1291728..119f7c98f3 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -71,6 +71,13 @@ class LLPanelRegionEnvironment;
class LLEventTimer;
+enum class ERefreshFromRegionPhase
+{
+ NotFromFloaterOpening,
+ BeforeRequestRegionInfo,
+ AfterRequestRegionInfo
+};
+
class LLFloaterRegionInfo : public LLFloater
{
friend class LLFloaterReg;
@@ -85,7 +92,7 @@ public:
// get and process region info if necessary.
static void processRegionInfo(LLMessageSystem* msg);
- static void sRefreshFromRegion(LLViewerRegion* region);
+ static void refreshFromRegion(LLViewerRegion* region);
static const LLUUID& getLastInvoice() { return sRequestInvoice; }
static void nextInvoice() { sRequestInvoice.generate(); }
@@ -104,7 +111,7 @@ public:
void refresh() override;
void onRegionChanged();
- void requestRegionInfo();
+ void requestRegionInfo(bool is_opening);
void enableTopButtons();
void disableTopButtons();
@@ -116,7 +123,7 @@ private:
protected:
void onTabSelected(const LLSD& param);
void disableTabCtrls();
- void refreshFromRegion(LLViewerRegion* region);
+ void refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase);
void onGodLevelChange(U8 god_level);
// member data
@@ -124,6 +131,7 @@ protected:
typedef std::vector<LLPanelRegionInfo*> info_panels_t;
info_panels_t mInfoPanels;
LLPanelRegionEnvironment *mEnvironmentPanel;
+ bool mIsRegionInfoRequestedFromOpening { false };
//static S32 sRequestSerial; // serial # of last EstateOwnerRequest
static LLUUID sRequestInvoice;
@@ -144,7 +152,7 @@ public:
void onChangeAnything();
static void onChangeText(LLLineEditor* caller, void* user_data);
- virtual bool refreshFromRegion(LLViewerRegion* region);
+ virtual bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase);
virtual bool estateUpdate(LLMessageSystem* msg) { return true; }
bool postBuild() override;
@@ -190,7 +198,7 @@ public:
: LLPanelRegionInfo() {}
~LLPanelRegionGeneralInfo() {}
- bool refreshFromRegion(LLViewerRegion* region) override;
+ bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override;
bool postBuild() override;
@@ -222,7 +230,7 @@ public:
bool postBuild() override;
- bool refreshFromRegion(LLViewerRegion* region) override;
+ bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override;
protected:
bool sendUpdate() override;
@@ -254,8 +262,8 @@ public:
bool postBuild() override;
- bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator
- void setEnvControls(bool available); // Whether environment settings are available for this region
+ bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override; // refresh local settings from region update from simulator
+ void setEnvControls(bool available); // Whether environment settings are available for this region
bool validateTextureSizes();
bool validateMaterials();
@@ -327,7 +335,7 @@ public:
static void updateEstateName(const std::string& name);
static void updateEstateOwnerName(const std::string& name);
- bool refreshFromRegion(LLViewerRegion* region) override;
+ bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override;
bool estateUpdate(LLMessageSystem* msg) override;
bool postBuild() override;
@@ -364,7 +372,7 @@ public:
bool postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
- bool refreshFromRegion(LLViewerRegion* region) override;
+ bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override;
bool estateUpdate(LLMessageSystem* msg) override;
// LLView overrides
@@ -430,7 +438,7 @@ public:
static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id);
static void infoCallback(LLHandle<LLPanelRegionExperiences> handle, const LLSD& content);
- bool refreshFromRegion(LLViewerRegion* region) override;
+ bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override;
void sendPurchaseRequest()const;
void processResponse( const LLSD& content );
@@ -470,7 +478,7 @@ public:
void setPendingUpdate(bool pending) { mPendingUpdate = pending; }
bool getPendingUpdate() { return mPendingUpdate; }
- bool refreshFromRegion(LLViewerRegion* region) override;
+ bool refreshFromRegion(LLViewerRegion* region, ERefreshFromRegionPhase phase) override;
private:
void onClickAddAllowedAgent();
diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h
index ee836dd00d..016c90f944 100644
--- a/indra/newview/llfloaterregionrestarting.h
+++ b/indra/newview/llfloaterregionrestarting.h
@@ -42,10 +42,10 @@ public:
private:
LLFloaterRegionRestarting(const LLSD& key);
virtual ~LLFloaterRegionRestarting();
- virtual bool postBuild();
- virtual bool tick();
- virtual void refresh();
- virtual void draw();
+ bool postBuild() override;
+ bool tick() override;
+ void refresh() override;
+ void draw() override;
virtual void regionChange();
std::string mName;
diff --git a/indra/newview/llfloaterscriptedprefs.cpp b/indra/newview/llfloaterscriptedprefs.cpp
index fa31cd72c1..fbeb256a9c 100644
--- a/indra/newview/llfloaterscriptedprefs.cpp
+++ b/indra/newview/llfloaterscriptedprefs.cpp
@@ -36,8 +36,8 @@ LLFloaterScriptEdPrefs::LLFloaterScriptEdPrefs(const LLSD& key)
: LLFloater(key)
, mEditor(NULL)
{
- mCommitCallbackRegistrar.add("ScriptPref.applyUIColor", boost::bind(&LLFloaterScriptEdPrefs::applyUIColor, this ,_1, _2));
- mCommitCallbackRegistrar.add("ScriptPref.getUIColor", boost::bind(&LLFloaterScriptEdPrefs::getUIColor, this ,_1, _2));
+ mCommitCallbackRegistrar.add("ScriptPref.applyUIColor", { boost::bind(&LLFloaterScriptEdPrefs::applyUIColor, this ,_1, _2) });
+ mCommitCallbackRegistrar.add("ScriptPref.getUIColor", { boost::bind(&LLFloaterScriptEdPrefs::getUIColor, this ,_1, _2) });
}
bool LLFloaterScriptEdPrefs::postBuild()
diff --git a/indra/newview/llfloatersettingscolor.cpp b/indra/newview/llfloatersettingscolor.cpp
index d9c382a1dc..1ca2412907 100644
--- a/indra/newview/llfloatersettingscolor.cpp
+++ b/indra/newview/llfloatersettingscolor.cpp
@@ -43,8 +43,8 @@ LLFloaterSettingsColor::LLFloaterSettingsColor(const LLSD& key)
: LLFloater(key),
mSettingList(NULL)
{
- mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsColor::onCommitSettings, this));
- mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsColor::onClickDefault, this));
+ mCommitCallbackRegistrar.add("CommitSettings", { boost::bind(&LLFloaterSettingsColor::onCommitSettings, this) });
+ mCommitCallbackRegistrar.add("ClickDefault", { boost::bind(&LLFloaterSettingsColor::onClickDefault, this) });
}
LLFloaterSettingsColor::~LLFloaterSettingsColor()
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index 8cc01f6dc6..0a01fff36d 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -34,14 +34,16 @@
#include "llcolorswatch.h"
#include "llviewercontrol.h"
#include "lltexteditor.h"
+#include "llclipboard.h"
+#include "llsdutil.h"
LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key)
: LLFloater(key),
mSettingList(NULL)
{
- mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this));
- mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this));
+ mCommitCallbackRegistrar.add("CommitSettings", { boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("ClickDefault", { boost::bind(&LLFloaterSettingsDebug::onClickDefault, this), cb_info::UNTRUSTED_BLOCK });
}
LLFloaterSettingsDebug::~LLFloaterSettingsDebug()
@@ -64,6 +66,8 @@ bool LLFloaterSettingsDebug::postBuild()
mSettingNameText = getChild<LLTextBox>("setting_name_txt");
mComment = getChild<LLTextEditor>("comment_text");
+ mLLSDVal = getChild<LLTextEditor>("llsd_text");
+ mCopyBtn = getChild<LLButton>("copy_btn");
getChild<LLFilterEditor>("filter_input")->setCommitCallback(boost::bind(&LLFloaterSettingsDebug::setSearchFilter, this, _2));
@@ -71,6 +75,8 @@ bool LLFloaterSettingsDebug::postBuild()
mSettingList->setCommitOnSelectionChange(true);
mSettingList->setCommitCallback(boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this));
+ mCopyBtn->setCommitCallback([this](LLUICtrl *ctrl, const LLSD &param) { onClickCopy(); });
+
updateList();
gSavedSettings.getControl("DebugSettingsHideDefault")->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::updateList, this, false));
@@ -205,6 +211,7 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
mSettingNameText->setVisible(true);
mSettingNameText->setText(controlp->getName());
mSettingNameText->setToolTip(controlp->getName());
+ mCopyBtn->setVisible(true);
mComment->setVisible(true);
std::string old_text = mComment->getText();
@@ -465,6 +472,17 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
mColorSwatch->setValue(sd);
break;
}
+ case TYPE_LLSD:
+ {
+ mLLSDVal->setVisible(true);
+ std::string new_text = ll_pretty_print_sd(sd);
+ // Don't setText if not nessesary, it will reset scroll
+ if (mLLSDVal->getText() != new_text)
+ {
+ mLLSDVal->setText(new_text);
+ }
+ break;
+ }
default:
mComment->setText(std::string("unknown"));
break;
@@ -631,7 +649,14 @@ void LLFloaterSettingsDebug::hideUIControls()
mValText->setVisible(false);
mDefaultButton->setVisible(false);
mBooleanCombo->setVisible(false);
+ mLLSDVal->setVisible(false);
mSettingNameText->setVisible(false);
+ mCopyBtn->setVisible(false);
mComment->setVisible(false);
}
+void LLFloaterSettingsDebug::onClickCopy()
+{
+ std::string setting_name = mSettingNameText->getText();
+ LLClipboard::instance().copyToClipboard(utf8str_to_wstring(setting_name), 0, narrow(setting_name.size()));
+}
diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h
index b813cf4a74..8849766867 100644
--- a/indra/newview/llfloatersettingsdebug.h
+++ b/indra/newview/llfloatersettingsdebug.h
@@ -49,6 +49,7 @@ public:
void onCommitSettings();
void onClickDefault();
+ void onClickCopy();
bool matchesSearchFilter(std::string setting_name);
bool isSettingHidden(LLControlVariable* control);
@@ -77,7 +78,9 @@ protected:
LLUICtrl* mBooleanCombo = nullptr;
LLUICtrl* mValText = nullptr;
LLUICtrl* mDefaultButton = nullptr;
+ LLTextEditor* mLLSDVal = nullptr;
LLTextBox* mSettingNameText = nullptr;
+ LLButton* mCopyBtn = nullptr;
LLColorSwatchCtrl* mColorSwatch = nullptr;
diff --git a/indra/newview/llfloatertestinspectors.cpp b/indra/newview/llfloatertestinspectors.cpp
index 7f8d122435..5b29dec6de 100644
--- a/indra/newview/llfloatertestinspectors.cpp
+++ b/indra/newview/llfloatertestinspectors.cpp
@@ -37,9 +37,9 @@ LLFloaterTestInspectors::LLFloaterTestInspectors(const LLSD& seed)
: LLFloater(seed)
{
mCommitCallbackRegistrar.add("ShowAvatarInspector",
- boost::bind(&LLFloaterTestInspectors::showAvatarInspector, this, _1, _2));
+ { boost::bind(&LLFloaterTestInspectors::showAvatarInspector, this, _1, _2) });
mCommitCallbackRegistrar.add("ShowObjectInspector",
- boost::bind(&LLFloaterTestInspectors::showObjectInspector, this, _1, _2));
+ { boost::bind(&LLFloaterTestInspectors::showObjectInspector, this, _1, _2) });
}
LLFloaterTestInspectors::~LLFloaterTestInspectors()
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index f6d8fcab36..5fe089aec5 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -387,21 +387,21 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
mFactoryMap["Contents"] = LLCallbackMap(createPanelContents, this);//LLPanelContents
mFactoryMap["land info panel"] = LLCallbackMap(createPanelLandInfo, this);//LLPanelLandInfo
- mCommitCallbackRegistrar.add("BuildTool.setTool", boost::bind(&LLFloaterTools::setTool,this, _2));
- mCommitCallbackRegistrar.add("BuildTool.commitZoom", boost::bind(&commit_slider_zoom, _1));
- mCommitCallbackRegistrar.add("BuildTool.commitRadioFocus", boost::bind(&commit_radio_group_focus, _1));
- mCommitCallbackRegistrar.add("BuildTool.commitRadioMove", boost::bind(&commit_radio_group_move,_1));
- mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", boost::bind(&commit_radio_group_edit,_1));
-
- mCommitCallbackRegistrar.add("BuildTool.gridMode", boost::bind(&commit_grid_mode,_1));
- mCommitCallbackRegistrar.add("BuildTool.selectComponent", boost::bind(&commit_select_component, this));
- mCommitCallbackRegistrar.add("BuildTool.gridOptions", boost::bind(&LLFloaterTools::onClickGridOptions,this));
- mCommitCallbackRegistrar.add("BuildTool.applyToSelection", boost::bind(&click_apply_to_selection, this));
- mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", boost::bind(&commit_radio_group_land,_1));
- mCommitCallbackRegistrar.add("BuildTool.LandBrushForce", boost::bind(&commit_slider_dozer_force,_1));
-
- mCommitCallbackRegistrar.add("BuildTool.LinkObjects", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
- mCommitCallbackRegistrar.add("BuildTool.UnlinkObjects", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
+ mCommitCallbackRegistrar.add("BuildTool.setTool", { boost::bind(&LLFloaterTools::setTool,this, _2) });
+ mCommitCallbackRegistrar.add("BuildTool.commitZoom", { boost::bind(&commit_slider_zoom, _1), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("BuildTool.commitRadioFocus", { boost::bind(&commit_radio_group_focus, _1), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("BuildTool.commitRadioMove", { boost::bind(&commit_radio_group_move,_1), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", { boost::bind(&commit_radio_group_edit,_1), cb_info::UNTRUSTED_BLOCK });
+
+ mCommitCallbackRegistrar.add("BuildTool.gridMode", { boost::bind(&commit_grid_mode,_1), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("BuildTool.selectComponent", { boost::bind(&commit_select_component, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("BuildTool.gridOptions", { boost::bind(&LLFloaterTools::onClickGridOptions,this) });
+ mCommitCallbackRegistrar.add("BuildTool.applyToSelection", { boost::bind(&click_apply_to_selection, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", { boost::bind(&commit_radio_group_land,_1), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("BuildTool.LandBrushForce", { boost::bind(&commit_slider_dozer_force,_1), cb_info::UNTRUSTED_BLOCK });
+
+ mCommitCallbackRegistrar.add("BuildTool.LinkObjects", { boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()) });
+ mCommitCallbackRegistrar.add("BuildTool.UnlinkObjects", { boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()) });
mLandImpactsObserver = new LLLandImpactsObserver();
LLViewerParcelMgr::getInstance()->addObserver(mLandImpactsObserver);
diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp
index 9bc8c63fa0..e379854160 100644
--- a/indra/newview/llfloatertopobjects.cpp
+++ b/indra/newview/llfloatertopobjects.cpp
@@ -76,16 +76,16 @@ LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key)
mInitialized(false),
mtotalScore(0.f)
{
- mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this));
- mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", boost::bind(&LLFloaterTopObjects::onReturnSelected, this));
- mCommitCallbackRegistrar.add("TopObjects.ReturnAll", boost::bind(&LLFloaterTopObjects::onReturnAll, this));
- mCommitCallbackRegistrar.add("TopObjects.Refresh", boost::bind(&LLFloaterTopObjects::onRefresh, this));
- mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", boost::bind(&LLFloaterTopObjects::onGetByObjectName, this));
- mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this));
- mCommitCallbackRegistrar.add("TopObjects.GetByParcelName", boost::bind(&LLFloaterTopObjects::onGetByParcelName, this));
- mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this));
-
- mCommitCallbackRegistrar.add("TopObjects.TeleportToSelected", boost::bind(&LLFloaterTopObjects::teleportToSelectedObject, this));
+ mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", { boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this) });
+ mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", { boost::bind(&LLFloaterTopObjects::onReturnSelected, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("TopObjects.ReturnAll", { boost::bind(&LLFloaterTopObjects::onReturnAll, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("TopObjects.Refresh", { boost::bind(&LLFloaterTopObjects::onRefresh, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", { boost::bind(&LLFloaterTopObjects::onGetByObjectName, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", { boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("TopObjects.GetByParcelName", { boost::bind(&LLFloaterTopObjects::onGetByParcelName, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",{ boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this), cb_info::UNTRUSTED_THROTTLE });
+
+ mCommitCallbackRegistrar.add("TopObjects.TeleportToSelected", { boost::bind(&LLFloaterTopObjects::teleportToSelectedObject, this), cb_info::UNTRUSTED_THROTTLE });
}
LLFloaterTopObjects::~LLFloaterTopObjects()
diff --git a/indra/newview/llfloatertoybox.cpp b/indra/newview/llfloatertoybox.cpp
index f6257dbd3d..f56b2aa962 100644
--- a/indra/newview/llfloatertoybox.cpp
+++ b/indra/newview/llfloatertoybox.cpp
@@ -41,8 +41,8 @@ LLFloaterToybox::LLFloaterToybox(const LLSD& key)
: LLFloater(key)
, mToolBar(NULL)
{
- mCommitCallbackRegistrar.add("Toybox.RestoreDefaults", boost::bind(&LLFloaterToybox::onBtnRestoreDefaults, this));
- mCommitCallbackRegistrar.add("Toybox.ClearAll", boost::bind(&LLFloaterToybox::onBtnClearAll, this));
+ mCommitCallbackRegistrar.add("Toybox.RestoreDefaults", { boost::bind(&LLFloaterToybox::onBtnRestoreDefaults, this) });
+ mCommitCallbackRegistrar.add("Toybox.ClearAll", { boost::bind(&LLFloaterToybox::onBtnClearAll, this) });
}
LLFloaterToybox::~LLFloaterToybox()
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 9bc075d03f..824d7fe98b 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -254,7 +254,7 @@ class LLFadeEventTimer : public LLEventTimer
{
public:
LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent);
- bool tick();
+ bool tick() override;
LLGUIPreviewLiveFile* mParent;
private:
bool mFadingOut; // fades in then out; this is toggled in between
diff --git a/indra/newview/llfloatervoiceeffect.cpp b/indra/newview/llfloatervoiceeffect.cpp
index 9f7c9aba87..45b6616d1e 100644
--- a/indra/newview/llfloatervoiceeffect.cpp
+++ b/indra/newview/llfloatervoiceeffect.cpp
@@ -36,9 +36,9 @@
LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& key)
: LLFloater(key)
{
- mCommitCallbackRegistrar.add("VoiceEffect.Record", boost::bind(&LLFloaterVoiceEffect::onClickRecord, this));
- mCommitCallbackRegistrar.add("VoiceEffect.Play", boost::bind(&LLFloaterVoiceEffect::onClickPlay, this));
- mCommitCallbackRegistrar.add("VoiceEffect.Stop", boost::bind(&LLFloaterVoiceEffect::onClickStop, this));
+ mCommitCallbackRegistrar.add("VoiceEffect.Record", { boost::bind(&LLFloaterVoiceEffect::onClickRecord, this) });
+ mCommitCallbackRegistrar.add("VoiceEffect.Play", { boost::bind(&LLFloaterVoiceEffect::onClickPlay, this) });
+ mCommitCallbackRegistrar.add("VoiceEffect.Stop", { boost::bind(&LLFloaterVoiceEffect::onClickStop, this) });
// mCommitCallbackRegistrar.add("VoiceEffect.Activate", boost::bind(&LLFloaterVoiceEffect::onClickActivate, this));
}
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index e1b6df6072..0cd20b7020 100644
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -75,13 +75,13 @@ LLFloaterWebContent::LLFloaterWebContent( const Params& params )
mDisplayURL(""),
mDevelopMode(params.dev_mode) // if called from "Develop" Menu, set a flag and change things to be more useful for devs
{
- mCommitCallbackRegistrar.add( "WebContent.Back", boost::bind( &LLFloaterWebContent::onClickBack, this ));
- mCommitCallbackRegistrar.add( "WebContent.Forward", boost::bind( &LLFloaterWebContent::onClickForward, this ));
- mCommitCallbackRegistrar.add( "WebContent.Reload", boost::bind( &LLFloaterWebContent::onClickReload, this ));
- mCommitCallbackRegistrar.add( "WebContent.Stop", boost::bind( &LLFloaterWebContent::onClickStop, this ));
- mCommitCallbackRegistrar.add( "WebContent.EnterAddress", boost::bind( &LLFloaterWebContent::onEnterAddress, this ));
- mCommitCallbackRegistrar.add( "WebContent.PopExternal", boost::bind(&LLFloaterWebContent::onPopExternal, this));
- mCommitCallbackRegistrar.add( "WebContent.TestURL", boost::bind(&LLFloaterWebContent::onTestURL, this, _2));
+ mCommitCallbackRegistrar.add( "WebContent.Back", { boost::bind( &LLFloaterWebContent::onClickBack, this ), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add( "WebContent.Forward", { boost::bind( &LLFloaterWebContent::onClickForward, this ), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add( "WebContent.Reload", { boost::bind( &LLFloaterWebContent::onClickReload, this ), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add( "WebContent.Stop", { boost::bind( &LLFloaterWebContent::onClickStop, this ), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add( "WebContent.EnterAddress", { boost::bind( &LLFloaterWebContent::onEnterAddress, this ), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add( "WebContent.PopExternal", { boost::bind(&LLFloaterWebContent::onPopExternal, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add( "WebContent.TestURL", { boost::bind(&LLFloaterWebContent::onTestURL, this, _2), cb_info::UNTRUSTED_BLOCK });
}
bool LLFloaterWebContent::postBuild()
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 30ed723db6..4674cd68b6 100755
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -337,17 +337,17 @@ LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, nullptr);
- mCommitCallbackRegistrar.add("WMap.Coordinates", boost::bind(&LLFloaterWorldMap::onCoordinatesCommit, this));
- mCommitCallbackRegistrar.add("WMap.Location", boost::bind(&LLFloaterWorldMap::onLocationCommit, this));
- mCommitCallbackRegistrar.add("WMap.AvatarCombo", boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this));
- mCommitCallbackRegistrar.add("WMap.Landmark", boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this));
- mCommitCallbackRegistrar.add("WMap.SearchResult", boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this));
- mCommitCallbackRegistrar.add("WMap.GoHome", boost::bind(&LLFloaterWorldMap::onGoHome, this));
- mCommitCallbackRegistrar.add("WMap.Teleport", boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this));
- mCommitCallbackRegistrar.add("WMap.ShowTarget", boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this));
- mCommitCallbackRegistrar.add("WMap.ShowAgent", boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this));
- mCommitCallbackRegistrar.add("WMap.Clear", boost::bind(&LLFloaterWorldMap::onClearBtn, this));
- mCommitCallbackRegistrar.add("WMap.CopySLURL", boost::bind(&LLFloaterWorldMap::onCopySLURL, this));
+ mCommitCallbackRegistrar.add("WMap.Coordinates", { boost::bind(&LLFloaterWorldMap::onCoordinatesCommit, this) });
+ mCommitCallbackRegistrar.add("WMap.Location", { boost::bind(&LLFloaterWorldMap::onLocationCommit, this) });
+ mCommitCallbackRegistrar.add("WMap.AvatarCombo", { boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this) });
+ mCommitCallbackRegistrar.add("WMap.Landmark", { boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this) });
+ mCommitCallbackRegistrar.add("WMap.SearchResult", { boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this) });
+ mCommitCallbackRegistrar.add("WMap.GoHome", { boost::bind(&LLFloaterWorldMap::onGoHome, this) });
+ mCommitCallbackRegistrar.add("WMap.Teleport", { boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this) });
+ mCommitCallbackRegistrar.add("WMap.ShowTarget", { boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this) });
+ mCommitCallbackRegistrar.add("WMap.ShowAgent", { boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this) });
+ mCommitCallbackRegistrar.add("WMap.Clear", { boost::bind(&LLFloaterWorldMap::onClearBtn, this) });
+ mCommitCallbackRegistrar.add("WMap.CopySLURL", { boost::bind(&LLFloaterWorldMap::onCopySLURL, this) });
gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterWorldMap::onChangeMaturity, this));
}
@@ -486,8 +486,11 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
const LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id);
- mLocationEditor->setFocus( true);
- gFocusMgr.triggerFocusFlash();
+ if (hasFocus())
+ {
+ mLocationEditor->setFocus( true);
+ gFocusMgr.triggerFocusFlash();
+ }
buildAvatarIDList();
buildLandmarkIDLists();
diff --git a/indra/newview/llflycam.cpp b/indra/newview/llflycam.cpp
new file mode 100644
index 0000000000..eb5bfecf73
--- /dev/null
+++ b/indra/newview/llflycam.cpp
@@ -0,0 +1,136 @@
+/**
+ * @file llflycam.cpp
+ * @brief LLFlycam class implementation
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llflycam.h"
+
+#include <algorithm>
+#include "llcamera.h"
+#include "llcoordframe.h"
+
+LLFlycam::LLFlycam()
+{
+}
+
+
+void LLFlycam::setTransform(const LLVector3& position, const LLQuaternion& rotation)
+{
+ mPosition = position;
+ mRotation = rotation;
+ mRotation.normalize();
+}
+
+void LLFlycam::getTransform(LLVector3& position_out, LLQuaternion& rotation_out)
+{
+ position_out = mPosition;
+ rotation_out = mRotation;
+}
+
+// 'view' is expected to be in radians
+void LLFlycam::setView(F32 view)
+{
+ mView = std::clamp(view, MIN_FIELD_OF_VIEW, MAX_FIELD_OF_VIEW);
+}
+
+
+void LLFlycam::setLinearVelocity(const LLVector3& velocity)
+{
+ // Note: this math expects velocity components to be in range [-1.0, 1.0]
+ mLinearVelocity = velocity;
+}
+
+
+void LLFlycam::setPitchRate(F32 pitch_rate)
+{
+ // Note: this math expects pitch_rate to be in range [-1.0, 1.0]
+ constexpr F32 PITCH_RATE_FACTOR = 0.75f;
+ mPitchRate = pitch_rate * PITCH_RATE_FACTOR;
+}
+
+
+void LLFlycam::setYawRate(F32 yaw_rate)
+{
+ // Note: this math expects yaw_rate to be in range [-1.0, 1.0]
+ constexpr F32 YAW_RATE_FACTOR = 0.90f;
+ mYawRate = yaw_rate * YAW_RATE_FACTOR;
+}
+
+
+void LLFlycam::setZoomRate(F32 zoom_rate)
+{
+ // Note: this math expects zoom_rate to be in range [-1.0, 1.0]
+ constexpr F32 FULL_ZOOM_PERIOD = 5.0f; // seconds
+ constexpr F32 ZOOM_RATE_FACTOR = (MAX_FIELD_OF_VIEW - MIN_FIELD_OF_VIEW) / FULL_ZOOM_PERIOD;
+ mZoomRate = zoom_rate * ZOOM_RATE_FACTOR;
+}
+
+
+void LLFlycam::integrate(F32 delta_time)
+{
+ // cap delta_time to slow camera motion when framerates are low
+ constexpr F32 MAX_DELTA_TIME = 0.2f;
+ if (delta_time > MAX_DELTA_TIME)
+ {
+ delta_time = MAX_DELTA_TIME;
+ }
+
+ // Note: we modulate pitch and yaw rates by view ratio
+ // to make pitch and yaw work better when zoomed in close
+ F32 angle = delta_time * mPitchRate * (mView / DEFAULT_FIELD_OF_VIEW);
+ bool needs_renormalization = false;
+ if (fabsf(angle) > 0.0f)
+ {
+ LLQuaternion dQ;
+ dQ.setAngleAxis(angle, 0.0f, 1.0f, 0.0f);
+ mRotation = dQ * mRotation;
+ needs_renormalization = true;
+ }
+
+ angle = delta_time * mYawRate * (mView / DEFAULT_FIELD_OF_VIEW);
+ if (fabsf(angle) > 0.0f)
+ {
+ LLQuaternion dQ;
+ dQ.setAngleAxis(angle, 0.0f, 0.0f, 1.0f);
+ mRotation = mRotation * dQ;
+ needs_renormalization = true;
+ }
+
+ if (mLinearVelocity.lengthSquared() > 0.0f)
+ {
+ mPosition += (delta_time * mLinearVelocity) * mRotation;
+ }
+
+ if (mZoomRate != 0.0f)
+ {
+ // Note: we subtract the delta because "positive" zoom (e.g. "zoom in")
+ // produces smaller view angle
+ mView = std::clamp(mView - delta_time * mZoomRate, MIN_FIELD_OF_VIEW, MAX_FIELD_OF_VIEW);
+ }
+
+ if (needs_renormalization)
+ {
+ mRotation.normalize();
+ }
+}
diff --git a/indra/newview/llflycam.h b/indra/newview/llflycam.h
new file mode 100644
index 0000000000..c75b6e246e
--- /dev/null
+++ b/indra/newview/llflycam.h
@@ -0,0 +1,60 @@
+/**
+ * @file llflycam.h
+ * @brief LLFlycam class header file
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "llcamera.h"
+#include "llquaternion.h"
+#include "v3math.h"
+
+class LLFlycam
+{
+public:
+
+ LLFlycam();
+
+ void setTransform(const LLVector3& position, const LLQuaternion& rotation);
+ void getTransform(LLVector3& position_out, LLQuaternion& rotation_out);
+
+ void setView(F32 view);
+ F32 getView() const { return mView; }
+
+ void setLinearVelocity(const LLVector3& velocity);
+ void setPitchRate(F32 pitch_rate);
+ void setYawRate(F32 yaw_rate);
+ void setZoomRate(F32 zoom_rate);
+
+ void integrate(F32 delta_time);
+
+protected:
+ LLVector3 mPosition;
+ LLVector3 mLinearVelocity;
+ LLQuaternion mRotation;
+ F32 mPitchRate { 0.0f };
+ F32 mYawRate { 0.0f };
+ F32 mZoomRate { 0.0f };
+ F32 mView { DEFAULT_FIELD_OF_VIEW };
+};
diff --git a/indra/newview/llflyoutcombobtn.cpp b/indra/newview/llflyoutcombobtn.cpp
index 728f60e1c0..97cd637da1 100644
--- a/indra/newview/llflyoutcombobtn.cpp
+++ b/indra/newview/llflyoutcombobtn.cpp
@@ -41,7 +41,7 @@ LLFlyoutComboBtnCtrl::LLFlyoutComboBtnCtrl(LLPanel* parent,
{
// register action mapping before creating menu
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar;
- save_registar.add("FlyoutCombo.Button.Action", [this](LLUICtrl *ctrl, const LLSD &data) { onFlyoutItemSelected(ctrl, data); });
+ save_registar.add("FlyoutCombo.Button.Action", { [this](LLUICtrl *ctrl, const LLSD &data) { onFlyoutItemSelected(ctrl, data); } });
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enabled_rgistar;
enabled_rgistar.add("FlyoutCombo.Button.Check", [this](LLUICtrl *ctrl, const LLSD &data) { return onFlyoutItemCheck(ctrl, data); });
diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp
index c668d414d3..9223c13ec1 100644
--- a/indra/newview/llfolderviewmodelinventory.cpp
+++ b/indra/newview/llfolderviewmodelinventory.cpp
@@ -68,9 +68,10 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )
if (!folder->areChildrenInited() || !needsSort(folder->getViewModelItem())) return;
- LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());
- if (modelp->getUUID().isNull()) return;
+ LLFolderViewModelItemInventory* sort_modelp = static_cast<LLFolderViewModelItemInventory*>(folder->getViewModelItem());
+ if (sort_modelp->getUUID().isNull()) return;
+ bool has_favorites = false;
for (std::list<LLFolderViewFolder*>::iterator it = folder->getFoldersBegin(), end_it = folder->getFoldersEnd();
it != end_it;
++it)
@@ -79,11 +80,14 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )
LLFolderViewFolder* child_folderp = *it;
sort(child_folderp);
+ LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(child_folderp->getViewModelItem());
+ has_favorites |= child_folderp->isFavorite() || child_folderp->hasFavorites();
+
if (child_folderp->getFoldersCount() > 0)
{
- time_t most_recent_folder_time =
- static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getFoldersBegin())->getViewModelItem())->getCreationDate();
- LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(child_folderp->getViewModelItem());
+ LLFolderViewModelItemInventory* folderp = static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getFoldersBegin())->getViewModelItem());
+ time_t most_recent_folder_time = folderp->getCreationDate();
+
if (most_recent_folder_time > modelp->getCreationDate())
{
modelp->setCreationDate(most_recent_folder_time);
@@ -91,16 +95,26 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder )
}
if (child_folderp->getItemsCount() > 0)
{
- time_t most_recent_item_time =
- static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getItemsBegin())->getViewModelItem())->getCreationDate();
+ LLFolderViewModelItemInventory* itemp = static_cast<LLFolderViewModelItemInventory*>((*child_folderp->getItemsBegin())->getViewModelItem());
+ time_t most_recent_item_time = itemp->getCreationDate();
- LLFolderViewModelItemInventory* modelp = static_cast<LLFolderViewModelItemInventory*>(child_folderp->getViewModelItem());
if (most_recent_item_time > modelp->getCreationDate())
{
modelp->setCreationDate(most_recent_item_time);
}
}
}
+ for (std::list<LLFolderViewItem*>::const_iterator it = folder->getItemsBegin(), end_it = folder->getItemsEnd();
+ it != end_it && !has_favorites;
+ ++it)
+ {
+ LLFolderViewItem* child_itemp = *it;
+ has_favorites |= child_itemp->isFavorite();
+ }
+ if (has_favorites)
+ {
+ folder->updateHasFavorites(true);
+ }
base_t::sort(folder);
}
diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h
index 48b4ee5fd9..04b0b6e8f4 100644
--- a/indra/newview/llfolderviewmodelinventory.h
+++ b/indra/newview/llfolderviewmodelinventory.h
@@ -48,6 +48,7 @@ public:
virtual bool isItemInTrash( void) const { return false; } // TODO: make into pure virtual.
virtual bool isItemInOutfits() const { return false; }
virtual bool isAgentInventory() const { return false; }
+ virtual bool isAgentInventoryRoot() const { return false; }
virtual bool isUpToDate() const = 0;
virtual void addChild(LLFolderViewModelItem* child);
virtual bool hasChildren() const = 0;
diff --git a/indra/newview/llgltffolderitem.h b/indra/newview/llgltffolderitem.h
index 89d90c81cc..a748e2fb6a 100644
--- a/indra/newview/llgltffolderitem.h
+++ b/indra/newview/llgltffolderitem.h
@@ -71,6 +71,7 @@ public:
void navigateToFolder(bool new_window = false, bool change_mode = false) override {}
+ bool isFavorite() const override { return false; }
bool isItemWearable() const override { return false; }
bool isItemRenameable() const override { return false; }
@@ -80,6 +81,7 @@ public:
void move(LLFolderViewModelItem* parent_listener) override {}
bool isItemRemovable(bool check_worn = true) const override { return false; }
+ bool isItemInTrash(void) const override { return false; }
bool removeItem() override { return false; }
void removeBatch(std::vector<LLFolderViewModelItem*>& batch) override {}
@@ -92,6 +94,9 @@ public:
void pasteFromClipboard() override {}
void pasteLinkFromClipboard() override {}
+ bool isAgentInventory() const override { return false; }
+ bool isAgentInventoryRoot() const override { return false; }
+
void buildContextMenu(LLMenuGL& menu, U32 flags) override {};
bool potentiallyVisible() override { return true; }; // is the item definitely visible or we haven't made up our minds yet?
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index 25438eae5e..5e5e6425b8 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -45,7 +45,9 @@
#include "llworld.h"
#include "tinygltf/tiny_gltf.h"
-#include <strstream>
+
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
#include <unordered_set>
@@ -168,7 +170,7 @@ namespace
void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::string& data_in)
{
- std::istringstream str(data_in);
+ boost::iostreams::stream<boost::iostreams::array_source> str(data_in.data(), data_in.size());
LLSD data;
@@ -539,8 +541,7 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp
LLSD asset;
// read file into buffer
- std::istrstream str(&buffer[0], static_cast<S32>(buffer.size()));
-
+ boost::iostreams::stream<boost::iostreams::array_source> str(buffer.data(), buffer.size());
if (LLSDSerialize::deserialize(asset, str, buffer.size()))
{
if (asset.has("version") && LLGLTFMaterial::isAcceptedVersion(asset["version"].asString()))
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index ba9c9fa13f..1128939e29 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -37,6 +37,7 @@
#include "llfloatersidepanelcontainer.h"
#include "llgroupmgr.h"
#include "llfloaterimcontainer.h"
+#include "llfloaterimsession.h"
#include "llimview.h" // for gIMMgr
#include "llnotificationsutil.h"
#include "llstartup.h"
@@ -46,7 +47,7 @@
//
// Globals
//
-static GroupChatListener sGroupChatListener;
+static LLGroupChatListener sGroupChatListener;
class LLGroupHandler : public LLCommandHandler
{
@@ -519,7 +520,10 @@ void LLGroupActions::endIM(const LLUUID& group_id)
LLUUID session_id = gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id);
if (session_id != LLUUID::null)
{
- gIMMgr->leaveSession(session_id);
+ if (LLFloaterIMSession *conversationFloater = LLFloaterIMSession::findInstance(session_id))
+ {
+ LLFloater::onClickClose(conversationFloater);
+ }
}
}
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 7659e5f082..14ac14cd85 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -141,7 +141,7 @@ void LLGroupList::enableForAgent(bool show_icons)
gAgent.addListener(this, "new group");
// Set up context menu.
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
registrar.add("People.Groups.Action", boost::bind(&LLGroupList::onContextMenuItemClick, this, _2));
diff --git a/indra/newview/llhudeffectresetskeleton.cpp b/indra/newview/llhudeffectresetskeleton.cpp
new file mode 100644
index 0000000000..31065a3e76
--- /dev/null
+++ b/indra/newview/llhudeffectresetskeleton.cpp
@@ -0,0 +1,211 @@
+/**
+ * @file llhudeffectresetskeleton.cpp
+ * @brief LLHUDEffectResetSkeleton class implementation
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llhudeffectresetskeleton.h"
+
+#include "llagent.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatar.h"
+#include "message.h"
+
+// packet layout
+const S32 TARGET_OBJECT = 0; // This is to allow for targetting owned animesh
+const S32 RESET_ANIMATIONS = 16; //This can also be a flags if needed
+const S32 PKT_SIZE = 17;
+
+//-----------------------------------------------------------------------------
+// LLHUDEffectResetSkeleton()
+//-----------------------------------------------------------------------------
+LLHUDEffectResetSkeleton::LLHUDEffectResetSkeleton(const U8 type) :
+ LLHUDEffect(type)
+{
+}
+
+//-----------------------------------------------------------------------------
+// ~LLHUDEffectResetSkeleton()
+//-----------------------------------------------------------------------------
+LLHUDEffectResetSkeleton::~LLHUDEffectResetSkeleton()
+{
+}
+
+//-----------------------------------------------------------------------------
+// packData()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::packData(LLMessageSystem *mesgsys)
+{
+ // Pack the default data
+ LLHUDEffect::packData(mesgsys);
+
+ // Pack the type-specific data. Uses a fun packed binary format. Whee!
+ U8 packed_data[PKT_SIZE];
+ memset(packed_data, 0, PKT_SIZE);
+
+ // pack both target object and position
+ // position interpreted as offset if target object is non-null
+ if (mTargetObject)
+ {
+ htolememcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16);
+ }
+ else
+ {
+ htolememcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16);
+ }
+
+ U8 resetAnimations = (U8)mResetAnimations;
+ htolememcpy(&(packed_data[RESET_ANIMATIONS]), &resetAnimations, MVT_U8, 1);
+
+ mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE);
+}
+
+//-----------------------------------------------------------------------------
+// unpackData()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
+{
+ LLVector3d new_target;
+ U8 packed_data[PKT_SIZE];
+
+
+ LLHUDEffect::unpackData(mesgsys, blocknum);
+
+ LLUUID source_id;
+ mesgsys->getUUIDFast(_PREHASH_Effect, _PREHASH_AgentID, source_id, blocknum);
+
+ LLViewerObject *objp = gObjectList.findObject(source_id);
+ if (objp && objp->isAvatar())
+ {
+ setSourceObject(objp);
+ }
+ else
+ {
+ //LL_WARNS() << "Could not find source avatar for ResetSkeleton effect" << LL_ENDL;
+ return;
+ }
+
+ S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
+ if (size != PKT_SIZE)
+ {
+ LL_WARNS() << "ResetSkeleton effect with bad size " << size << LL_ENDL;
+ return;
+ }
+
+ mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum);
+
+ LLUUID target_id;
+ htolememcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16);
+
+ // The purpose for having a target ID is if we want to reset animesh, or
+ // other things in the future.
+ // I implemented this, but due to issues regarding various permission
+ // checks, I scrapped it for now. --Chaser Zaks
+ // See https://github.com/secondlife/viewer/pull/1212 for additional info
+
+ if (target_id.isNull())
+ {
+ target_id = source_id;
+ }
+
+ objp = gObjectList.findObject(target_id);
+
+ if (objp)
+ {
+ setTargetObject(objp);
+ }
+
+ U8 resetAnimations = 0;
+ htolememcpy(&resetAnimations, &(packed_data[RESET_ANIMATIONS]), MVT_U8, 1);
+
+ // Pre-emptively assume this is going to be flags in the future.
+ // It isn't needed now, but this will assure that only bit 1 is set
+ mResetAnimations = resetAnimations & 1;
+
+ update();
+}
+
+//-----------------------------------------------------------------------------
+// setTargetObjectAndOffset()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::setTargetObject(LLViewerObject *objp)
+{
+ mTargetObject = objp;
+}
+
+
+//-----------------------------------------------------------------------------
+// markDead()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::markDead()
+{
+ LLHUDEffect::markDead();
+}
+
+void LLHUDEffectResetSkeleton::setSourceObject(LLViewerObject* objectp)
+{
+ // restrict source objects to avatars
+ if (objectp && objectp->isAvatar())
+ {
+ LLHUDEffect::setSourceObject(objectp);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// update()
+//-----------------------------------------------------------------------------
+void LLHUDEffectResetSkeleton::update()
+{
+ // If the target object is dead, set the target object to NULL
+ if (mTargetObject.isNull() || mTargetObject->isDead())
+ {
+ markDead();
+ return;
+ }
+
+ if (mSourceObject.isNull() || mSourceObject->isDead())
+ {
+ markDead();
+ return;
+ }
+
+ if (mTargetObject->isAvatar())
+ {
+ // Only the owner of a avatar can reset their skeleton like this
+ // Also allow reset if we created the effect (Local resetting)
+ if (mSourceObject->getID() == mTargetObject->getID() || getOriginatedHere())
+ {
+ LLVOAvatar* avatar = mTargetObject->asAvatar();
+ avatar->resetSkeleton(mResetAnimations);
+ }
+ }
+ else
+ {
+ LL_WARNS() << mSourceObject->getID() << " attempted to reset skeleton on "
+ << mTargetObject->getID() << ", but it is not a avatar!" << LL_ENDL;
+ }
+
+ markDead();
+}
diff --git a/indra/newview/llhudeffectresetskeleton.h b/indra/newview/llhudeffectresetskeleton.h
new file mode 100644
index 0000000000..39a6137054
--- /dev/null
+++ b/indra/newview/llhudeffectresetskeleton.h
@@ -0,0 +1,59 @@
+/**
+ * @file llhudeffectresetskeleton.h
+ * @brief LLHUDEffectResetSkeleton class definition
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLHUDEFFECTRESETSKELETON_H
+#define LL_LLHUDEFFECTRESETSKELETON_H
+
+#include "llhudeffect.h"
+
+class LLViewerObject;
+class LLVOAvatar;
+
+
+class LLHUDEffectResetSkeleton final : public LLHUDEffect
+{
+public:
+ friend class LLHUDObject;
+
+ /*virtual*/ void markDead();
+ /*virtual*/ void setSourceObject(LLViewerObject* objectp);
+
+ void setTargetObject(LLViewerObject *objp);
+ void setResetAnimations(bool enable){ mResetAnimations = enable; };
+
+protected:
+ LLHUDEffectResetSkeleton(const U8 type);
+ ~LLHUDEffectResetSkeleton();
+
+ /*virtual*/ void packData(LLMessageSystem *mesgsys);
+ /*virtual*/ void unpackData(LLMessageSystem *mesgsys, S32 blocknum);
+
+ void update();
+private:
+ bool mResetAnimations;
+};
+
+#endif // LL_LLHUDEFFECTRESETSKELETON_H
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 11f049564a..66130a2744 100644
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -275,7 +275,8 @@ void LLHUDNameTag::renderText()
LLVector3 x_pixel_vec;
LLVector3 y_pixel_vec;
- LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ camera->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
LLVector3 width_vec = mWidth * x_pixel_vec;
LLVector3 height_vec = mHeight * y_pixel_vec;
@@ -283,13 +284,22 @@ void LLHUDNameTag::renderText()
mRadius = (width_vec + height_vec).magVec() * 0.5f;
LLCoordGL screen_pos;
- LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, false);
+ camera->projectPosAgentToScreen(mPositionAgent, screen_pos, false);
LLVector2 screen_offset = updateScreenPos(mPositionOffset);
LLVector3 render_position = mPositionAgent
+ (x_pixel_vec * screen_offset.mV[VX])
+ (y_pixel_vec * screen_offset.mV[VY]);
+ bool reset_buffers = false;
+ const F32 treshold = 0.000001f;
+ if (abs(mLastRenderPosition.mV[VX] - render_position.mV[VX]) > treshold
+ || abs(mLastRenderPosition.mV[VY] - render_position.mV[VY]) > treshold
+ || abs(mLastRenderPosition.mV[VZ] - render_position.mV[VZ]) > treshold)
+ {
+ reset_buffers = true;
+ mLastRenderPosition = render_position;
+ }
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
LLRect screen_rect;
@@ -301,7 +311,7 @@ void LLHUDNameTag::renderText()
const S32 label_height = ll_round((mFontp->getLineHeight() * (F32)mLabelSegments.size() + (VERTICAL_PADDING / 3.f)));
label_top_rect.mBottom = label_top_rect.mTop - label_height;
LLColor4 label_top_color = text_color;
- label_top_color.mV[VALPHA] = gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor;
+ label_top_color.mV[VALPHA] = bubble_opacity() * alpha_factor;
mRoundedRectTopImgp->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color);
}
@@ -313,6 +323,11 @@ void LLHUDNameTag::renderText()
for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
segment_iter != mLabelSegments.end(); ++segment_iter )
{
+ if (reset_buffers)
+ {
+ segment_iter->mFontBufferLabel.reset();
+ }
+
// Label segments use default font
const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
y_offset -= fontp->getLineHeight();
@@ -328,7 +343,7 @@ void LLHUDNameTag::renderText()
}
LLColor4 label_color(0.f, 0.f, 0.f, alpha_factor);
- hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, false);
+ hud_render_text(segment_iter->getText(), render_position, &segment_iter->mFontBufferLabel, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, false);
}
}
@@ -350,6 +365,11 @@ void LLHUDNameTag::renderText()
for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
segment_iter != mTextSegments.end(); ++segment_iter )
{
+ if (reset_buffers)
+ {
+ segment_iter->mFontBufferText.reset();
+ }
+
const LLFontGL* fontp = segment_iter->mFont;
y_offset -= fontp->getLineHeight();
y_offset -= LINE_PADDING;
@@ -373,7 +393,7 @@ void LLHUDNameTag::renderText()
text_color = segment_iter->mColor;
text_color.mV[VALPHA] *= alpha_factor;
- hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, false);
+ hud_render_text(segment_iter->getText(), render_position, &segment_iter->mFontBufferText, *fontp, style, shadow, x_offset, y_offset, text_color, false);
}
}
/// Reset the default color to white. The renderer expects this to be the default.
@@ -626,12 +646,13 @@ LLVector2 LLHUDNameTag::updateScreenPos(LLVector2 &offset)
LLVector2 screen_pos_vec;
LLVector3 x_pixel_vec;
LLVector3 y_pixel_vec;
- LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ camera->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);
LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec);
- if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, false) && mVisibleOffScreen)
+ if (!camera->projectPosAgentToScreen(world_pos, screen_pos, false) && mVisibleOffScreen)
{
// bubble off-screen, so find a spot for it along screen edge
- LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos);
+ camera->projectPosAgentToScreenEdge(world_pos, screen_pos);
}
screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY);
diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h
index ee66187345..b48a606982 100644
--- a/indra/newview/llhudnametag.h
+++ b/indra/newview/llhudnametag.h
@@ -68,6 +68,8 @@ protected:
LLColor4 mColor;
LLFontGL::StyleFlags mStyle;
const LLFontGL* mFont;
+ LLFontVertexBuffer mFontBufferLabel;
+ LLFontVertexBuffer mFontBufferText;
private:
LLWString mText;
std::map<const LLFontGL*, F32> mFontWidthMap;
@@ -175,6 +177,7 @@ private:
S32 mMaxLines;
S32 mOffsetY;
F32 mRadius;
+ LLVector3 mLastRenderPosition;
std::vector<LLHUDTextSegment> mTextSegments;
std::vector<LLHUDTextSegment> mLabelSegments;
// LLFrameTimer mResizeTimer;
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index e6fbfbfb38..04e9e2dff2 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -36,6 +36,7 @@
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llhudeffectpointat.h"
+#include "llhudeffectresetskeleton.h"
#include "llhudnametag.h"
#include "llvoicevisualizer.h"
@@ -241,6 +242,9 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type)
case LL_HUD_EFFECT_BLOB:
hud_objectp = new LLHUDEffectBlob(type);
break;
+ case LL_HUD_EFFECT_RESET_SKELETON:
+ hud_objectp = new LLHUDEffectResetSkeleton(type);
+ break;
default:
LL_WARNS() << "Unknown type of hud effect:" << (U32) type << LL_ENDL;
}
diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h
index 8c628e3f92..f683f21e96 100644
--- a/indra/newview/llhudobject.h
+++ b/indra/newview/llhudobject.h
@@ -96,7 +96,8 @@ public:
LL_HUD_EFFECT_POINTAT,
LL_HUD_EFFECT_VOICE_VISUALIZER, // Ventrella
LL_HUD_NAME_TAG,
- LL_HUD_EFFECT_BLOB
+ LL_HUD_EFFECT_BLOB,
+ LL_HUD_EFFECT_RESET_SKELETON
};
protected:
static void sortObjects();
diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp
index 135fba7897..2255eb236f 100644
--- a/indra/newview/llhudrender.cpp
+++ b/indra/newview/llhudrender.cpp
@@ -42,6 +42,7 @@
#include <glm/gtc/type_ptr.hpp>
void hud_render_utf8text(const std::string &str, const LLVector3 &pos_agent,
+ LLFontVertexBuffer *font_buffer,
const LLFontGL &font,
const U8 style,
const LLFontGL::ShadowType shadow,
@@ -50,10 +51,11 @@ void hud_render_utf8text(const std::string &str, const LLVector3 &pos_agent,
const bool orthographic)
{
LLWString wstr(utf8str_to_wstring(str));
- hud_render_text(wstr, pos_agent, font, style, shadow, x_offset, y_offset, color, orthographic);
+ hud_render_text(wstr, pos_agent, font_buffer, font, style, shadow, x_offset, y_offset, color, orthographic);
}
void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
+ LLFontVertexBuffer *font_buffer,
const LLFontGL &font,
const U8 style,
const LLFontGL::ShadowType shadow,
@@ -61,6 +63,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
const LLColor4& color,
const bool orthographic)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
LLViewerCamera* camera = LLViewerCamera::getInstance();
// Do cheap plane culling
LLVector3 dir_vec = pos_agent - camera->getOrigin();
@@ -106,7 +109,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
LLRect world_view_rect = gViewerWindow->getWorldViewRectRaw();
glm::ivec4 viewport(world_view_rect.mLeft, world_view_rect.mBottom, world_view_rect.getWidth(), world_view_rect.getHeight());
- glm::vec3 win_coord = glm::project(glm::make_vec3(render_pos.mV), get_current_modelview(), get_current_projection(), viewport);
+ glm::vec3 win_coord = glm::project(glm::make_vec3(LLVector4(render_pos).mV), get_current_modelview(), get_current_projection(), viewport);
//fonts all render orthographically, set up projection``
gGL.matrixMode(LLRender::MM_PROJECTION);
@@ -125,7 +128,14 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
LLUI::translate((F32) win_coord.x*1.0f/LLFontGL::sScaleX, (F32) win_coord.y*1.0f/(LLFontGL::sScaleY), -(((F32) win_coord.z*2.f)-1.f));
F32 right_x;
- font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, static_cast<S32>(wstr.length()), 1000, &right_x, /*use_ellipses*/false, /*use_color*/true);
+ if (font_buffer)
+ {
+ font_buffer->render(&font, wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, static_cast<S32>(wstr.length()), 1000, &right_x, /*use_ellipses*/false, /*use_color*/true);
+ }
+ else
+ {
+ font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, static_cast<S32>(wstr.length()), 1000, &right_x, /*use_ellipses*/false, /*use_color*/true);
+ }
LLUI::popMatrix();
gGL.popMatrix();
diff --git a/indra/newview/llhudrender.h b/indra/newview/llhudrender.h
index 3c71acb271..be9fc7f084 100644
--- a/indra/newview/llhudrender.h
+++ b/indra/newview/llhudrender.h
@@ -36,6 +36,7 @@ class LLFontGL;
// Utility classes for rendering HUD elements
void hud_render_text(const LLWString &wstr,
const LLVector3 &pos_agent,
+ LLFontVertexBuffer *font_buffer,
const LLFontGL &font,
const U8 style,
const LLFontGL::ShadowType,
@@ -47,6 +48,7 @@ void hud_render_text(const LLWString &wstr,
// Legacy, slower
void hud_render_utf8text(const std::string &str,
const LLVector3 &pos_agent,
+ LLFontVertexBuffer *font_buffer,
const LLFontGL &font,
const U8 style,
const LLFontGL::ShadowType,
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index fd0d8b696f..818474a0cb 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -185,6 +185,15 @@ void LLHUDText::renderText()
LLVector3 render_position = mPositionAgent
+ (x_pixel_vec * screen_offset.mV[VX])
+ (y_pixel_vec * screen_offset.mV[VY]);
+ bool reset_buffers = false;
+ const F32 treshold = 0.000001f;
+ if (abs(mLastRenderPosition.mV[VX] - render_position.mV[VX]) > treshold
+ || abs(mLastRenderPosition.mV[VY] - render_position.mV[VY]) > treshold
+ || abs(mLastRenderPosition.mV[VZ] - render_position.mV[VZ]) > treshold)
+ {
+ reset_buffers = true;
+ mLastRenderPosition = render_position;
+ }
F32 y_offset = (F32)mOffsetY;
@@ -208,6 +217,11 @@ void LLHUDText::renderText()
for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
segment_iter != mTextSegments.end(); ++segment_iter )
{
+ if (reset_buffers)
+ {
+ segment_iter->mFontBufferText.reset();
+ }
+
const LLFontGL* fontp = segment_iter->mFont;
y_offset -= fontp->getLineHeight() - 1; // correction factor to match legacy font metrics
@@ -231,7 +245,7 @@ void LLHUDText::renderText()
}
text_color.mV[VALPHA] *= alpha_factor;
- hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, mOnHUDAttachment);
+ hud_render_text(segment_iter->getText(), render_position, &segment_iter->mFontBufferText, *fontp, style, shadow, x_offset, y_offset, text_color, mOnHUDAttachment);
}
}
/// Reset the default color to white. The renderer expects this to be the default.
diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h
index 3bc33f1478..4c850e2d91 100644
--- a/indra/newview/llhudtext.h
+++ b/indra/newview/llhudtext.h
@@ -68,6 +68,7 @@ protected:
LLFontGL::StyleFlags mStyle;
const LLFontGL* mFont;
LLFontVertexBuffer mFontBuffer;
+ LLFontVertexBuffer mFontBufferText;
private:
LLWString mText;
std::map<const LLFontGL*, F32> mFontWidthMap;
@@ -153,6 +154,7 @@ private:
const LLFontGL* mBoldFontp;
LLRectf mSoftScreenRect;
LLVector3 mPositionAgent;
+ LLVector3 mLastRenderPosition;
LLVector2 mPositionOffset;
LLVector2 mTargetPositionOffset;
F32 mMass;
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index 590cd09a31..e050fb77e0 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -422,6 +422,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
U8 *binary_bucket,
S32 binary_bucket_size,
LLHost &sender,
+ LLSD metadata,
LLUUID aux_id)
{
LLChat chat;
@@ -451,6 +452,28 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
bool is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
LLMuteList::isLinden(name);
+ /***
+ * The simulator may have flagged this sender as a bot, if the viewer would like to display
+ * the chat text in a different color or font, the below code is how the viewer can
+ * tell if the sender is a bot.
+ *-----------------------------------------------------
+ bool is_bot = false;
+ if (metadata.has("sender"))
+ { // The server has identified this sender as a bot.
+ is_bot = metadata["sender"]["bot"].asBoolean();
+ }
+ *-----------------------------------------------------
+ */
+
+ std::string notice_name;
+ LLSD notice_args;
+ if (metadata.has("notice"))
+ { // The server has injected a notice into the IM conversation.
+ // These will be things like bot notifications, etc.
+ notice_name = metadata["notice"]["id"].asString();
+ notice_args = metadata["notice"]["data"];
+ }
+
chat.mMuted = is_muted;
chat.mFromID = from_id;
chat.mFromName = name;
@@ -544,7 +567,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
}
else
{
- // standard message, not from system
+ // standard message, server may have injected a notice into the conversation.
std::string saved;
if (offline == IM_OFFLINE)
{
@@ -579,8 +602,17 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
region_message = true;
}
}
- gIMMgr->addMessage(
- session_id,
+
+ std::string real_name;
+
+ if (!notice_name.empty())
+ { // The simulator has injected some sort of notice into the conversation.
+ // findString will only replace the contents of buffer if the notice_id is found.
+ LLTrans::findString(buffer, notice_name, notice_args);
+ real_name = SYSTEM_FROM;
+ }
+
+ gIMMgr->addMessage(session_id,
from_id,
name,
buffer,
@@ -591,7 +623,9 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
region_id,
position,
region_message,
- timestamp);
+ timestamp,
+ LLUUID::null,
+ real_name);
}
else
{
@@ -1627,6 +1661,12 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
from_group = message_data["from_group"].asString() == "Y";
}
+ LLSD metadata;
+ if (message_data.has("metadata"))
+ {
+ metadata = message_data["metadata"];
+ }
+
EInstantMessage dialog = static_cast<EInstantMessage>(message_data["dialog"].asInteger());
LLUUID session_id = message_data["transaction-id"].asUUID();
if (session_id.isNull() && dialog == IM_FROM_TASK)
@@ -1654,6 +1694,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
local_bin_bucket.data(),
S32(local_bin_bucket.size()),
local_sender,
+ metadata,
message_data["asset_id"].asUUID());
});
diff --git a/indra/newview/llimprocessing.h b/indra/newview/llimprocessing.h
index 030d28b198..66ffc59ae0 100644
--- a/indra/newview/llimprocessing.h
+++ b/indra/newview/llimprocessing.h
@@ -48,6 +48,7 @@ public:
U8 *binary_bucket,
S32 binary_bucket_size,
LLHost &sender,
+ LLSD metadata,
LLUUID aux_id = LLUUID::null);
// Either receives list of offline messages from 'ReadOfflineMsgs' capability
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index f800210eba..a2fc124b26 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -1692,6 +1692,8 @@ bool LLIMModel::logToFile(const std::string& file_name, const std::string& from,
}
else
{
+ // will check KeepConversationLogTranscripts on its own
+ LLConversationLog::instance().cache();
return false;
}
}
@@ -3145,9 +3147,16 @@ void LLIMMgr::addMessage(
const LLUUID& region_id,
const LLVector3& position,
bool is_region_msg,
- U32 timestamp) // May be zero
+ U32 timestamp, // May be zero
+ LLUUID display_id,
+ std::string_view display_name)
{
LLUUID other_participant_id = target_id;
+ std::string message_display_name = (display_name.empty()) ? from : std::string(display_name);
+ if (display_id.isNull() && (display_name.empty()))
+ {
+ display_id = other_participant_id;
+ }
LLUUID new_session_id = session_id;
if (new_session_id.isNull())
@@ -3243,7 +3252,7 @@ void LLIMMgr::addMessage(
}
//Play sound for new conversations
- if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation")))
+ if (!skip_message && !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation")))
{
make_ui_sound("UISndNewIncomingIMSession");
}
@@ -3257,7 +3266,7 @@ void LLIMMgr::addMessage(
if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message)
{
- LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp);
+ LLIMModel::instance().addMessage(new_session_id, message_display_name, display_id, msg, true, is_region_msg, timestamp);
}
// Open conversation floater if offline messages are present
@@ -3553,6 +3562,7 @@ void LLIMMgr::inviteToSession(
&& voice_invite && "VoiceInviteQuestionDefault" == question_type)
{
LL_INFOS("IMVIEW") << "Rejecting voice call from initiating muted resident " << caller_name << LL_ENDL;
+ payload["voice_channel_info"] = voice_channel_info;
LLIncomingCallDialog::processCallResponse(1, payload);
return;
}
@@ -3601,6 +3611,7 @@ void LLIMMgr::inviteToSession(
send_do_not_disturb_message(gMessageSystem, caller_id, session_id);
}
// silently decline the call
+ payload["voice_channel_info"] = voice_channel_info;
LLIncomingCallDialog::processCallResponse(1, payload);
return;
}
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index 99b19c9fa9..162a8d93dd 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -51,7 +51,7 @@ class LLSessionTimeoutTimer : public LLEventTimer
public:
LLSessionTimeoutTimer(const LLUUID& session_id, F32 period) : LLEventTimer(period), mSessionId(session_id) {}
virtual ~LLSessionTimeoutTimer() {};
- /* virtual */ bool tick();
+ bool tick() override;
private:
LLUUID mSessionId;
@@ -368,7 +368,9 @@ public:
const LLUUID& region_id = LLUUID::null,
const LLVector3& position = LLVector3::zero,
bool is_region_msg = false,
- U32 timestamp = 0);
+ U32 timestamp = 0,
+ LLUUID display_id = LLUUID::null,
+ std::string_view display_name = "");
void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args);
diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp
index db48061c56..c39380105b 100644
--- a/indra/newview/llinspectgroup.cpp
+++ b/indra/newview/llinspectgroup.cpp
@@ -97,11 +97,11 @@ LLInspectGroup::LLInspectGroup(const LLSD& sd)
mGroupID() // set in onOpen()
{
mCommitCallbackRegistrar.add("InspectGroup.ViewProfile",
- boost::bind(&LLInspectGroup::onClickViewProfile, this));
+ { boost::bind(&LLInspectGroup::onClickViewProfile, this), cb_info::UNTRUSTED_THROTTLE });
mCommitCallbackRegistrar.add("InspectGroup.Join",
- boost::bind(&LLInspectGroup::onClickJoin, this));
+ { boost::bind(&LLInspectGroup::onClickJoin, this), cb_info::UNTRUSTED_THROTTLE });
mCommitCallbackRegistrar.add("InspectGroup.Leave",
- boost::bind(&LLInspectGroup::onClickLeave, this));
+ { boost::bind(&LLInspectGroup::onClickLeave, this), cb_info::UNTRUSTED_BLOCK });
// can't make the properties request until the widgets are constructed
// as it might return immediately, so do it in postBuild.
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index eb2cdb8632..874ad41551 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -129,14 +129,14 @@ LLInspectObject::LLInspectObject(const LLSD& sd)
{
// can't make the properties request until the widgets are constructed
// as it might return immediately, so do it in postBuild.
- mCommitCallbackRegistrar.add("InspectObject.Buy", boost::bind(&LLInspectObject::onClickBuy, this));
- mCommitCallbackRegistrar.add("InspectObject.Pay", boost::bind(&LLInspectObject::onClickPay, this));
- mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy", boost::bind(&LLInspectObject::onClickTakeFreeCopy, this));
- mCommitCallbackRegistrar.add("InspectObject.Touch", boost::bind(&LLInspectObject::onClickTouch, this));
- mCommitCallbackRegistrar.add("InspectObject.Sit", boost::bind(&LLInspectObject::onClickSit, this));
- mCommitCallbackRegistrar.add("InspectObject.Open", boost::bind(&LLInspectObject::onClickOpen, this));
- mCommitCallbackRegistrar.add("InspectObject.MoreInfo", boost::bind(&LLInspectObject::onClickMoreInfo, this));
- mCommitCallbackRegistrar.add("InspectObject.ZoomIn", boost::bind(&LLInspectObject::onClickZoomIn, this));
+ mCommitCallbackRegistrar.add("InspectObject.Buy", {boost::bind(&LLInspectObject::onClickBuy, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("InspectObject.Pay", {boost::bind(&LLInspectObject::onClickPay, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy", {boost::bind(&LLInspectObject::onClickTakeFreeCopy, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("InspectObject.Touch", {boost::bind(&LLInspectObject::onClickTouch, this), cb_info::UNTRUSTED_BLOCK});
+ mCommitCallbackRegistrar.add("InspectObject.Sit", {boost::bind(&LLInspectObject::onClickSit, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("InspectObject.Open", {boost::bind(&LLInspectObject::onClickOpen, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("InspectObject.MoreInfo", {boost::bind(&LLInspectObject::onClickMoreInfo, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("InspectObject.ZoomIn", {boost::bind(&LLInspectObject::onClickZoomIn, this), cb_info::UNTRUSTED_BLOCK});
}
diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp
index 24dbe61bad..0482befdcb 100644
--- a/indra/newview/llinspecttexture.cpp
+++ b/indra/newview/llinspecttexture.cpp
@@ -115,7 +115,6 @@ public:
protected:
LLPointer<LLViewerFetchedTexture> m_Image;
- S32 mImageBoostLevel = LLGLTexture::BOOST_NONE;
std::string mLoadingText;
};
@@ -128,11 +127,7 @@ LLTexturePreviewView::LLTexturePreviewView(const LLView::Params& p)
LLTexturePreviewView::~LLTexturePreviewView()
{
- if (m_Image)
- {
- m_Image->setBoostLevel(mImageBoostLevel);
- m_Image = nullptr;
- }
+ m_Image = nullptr;
}
void LLTexturePreviewView::draw()
@@ -153,19 +148,19 @@ void LLTexturePreviewView::draw()
bool isLoading = (!m_Image->isFullyLoaded()) && (m_Image->getDiscardLevel() > 0);
if (isLoading)
LLFontGL::getFontSansSerif()->renderUTF8(mLoadingText, 0, rctClient.mLeft + 3, rctClient.mTop - 25, LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
- m_Image->addTextureStats((isLoading) ? MAX_IMAGE_AREA : (F32)(rctClient.getWidth() * rctClient.getHeight()));
+
+ m_Image->setKnownDrawSize(MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
}
}
void LLTexturePreviewView::setImageFromAssetId(const LLUUID& idAsset)
{
- m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+ m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_THUMBNAIL);
if (m_Image)
{
- mImageBoostLevel = m_Image->getBoostLevel();
- m_Image->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
m_Image->forceToSaveRawImage(0);
- if ( (!m_Image->isFullyLoaded()) && (!m_Image->hasFetcher()) )
+ m_Image->setKnownDrawSize(MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
+ if ((!m_Image->isFullyLoaded()) && (!m_Image->hasFetcher()))
{
if (m_Image->isInFastCacheList())
{
@@ -179,7 +174,7 @@ void LLTexturePreviewView::setImageFromAssetId(const LLUUID& idAsset)
void LLTexturePreviewView::setImageFromItemId(const LLUUID& idItem)
{
const LLViewerInventoryItem* pItem = gInventory.getItem(idItem);
- setImageFromAssetId( (pItem) ? pItem->getAssetUUID() : LLUUID::null );
+ setImageFromAssetId( (pItem) ? pItem->getAssetUUID() : LLUUID::null);
}
// ============================================================================
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index d511171679..a002ed0534 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -830,6 +830,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
{
const LLInventoryObject *obj = getInventoryObject();
bool single_folder_root = (mRoot == NULL);
+ bool is_cof = isCOFFolder();
+ bool is_inbox = isInboxFolder();
if (obj)
{
@@ -844,7 +846,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
disabled_items.push_back(std::string("Copy"));
}
- if (isAgentInventory() && !single_folder_root && !isMarketplaceListingsFolder())
+ bool is_agent_inventory = isAgentInventory();
+ if (is_agent_inventory && !single_folder_root && !is_cof && !is_inbox && !isMarketplaceListingsFolder())
{
items.push_back(std::string("New folder from selected"));
items.push_back(std::string("Subfolder Separator"));
@@ -857,6 +860,19 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
}
+ if (isFavorite())
+ {
+ items.push_back(std::string("Remove from Favorites"));
+ }
+ else if (is_agent_inventory && !gInventory.isObjectDescendentOf(mUUID, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
+ {
+ items.push_back(std::string("Add to Favorites"));
+ if (gInventory.getRootFolderID() == mUUID)
+ {
+ disabled_items.push_back(std::string("Add to Favorites"));
+ }
+ }
+
if (obj->getIsLinkType())
{
items.push_back(std::string("Find Original"));
@@ -869,6 +885,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
+ disabled_items.push_back(std::string("New folder from selected"));
}
}
else
@@ -878,7 +895,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
items.push_back(std::string("Find Links"));
}
- if (!isInboxFolder() && !single_folder_root)
+ if (!is_inbox && !single_folder_root)
{
items.push_back(std::string("Rename"));
if (!isItemRenameable() || ((flags & FIRST_SELECTED_ITEM) == 0))
@@ -918,6 +935,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
+ disabled_items.push_back(std::string("New folder from selected"));
}
if (canListOnMarketplace() && !isMarketplaceListingsFolder() && !isInboxFolder())
@@ -940,7 +958,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
// Don't allow items to be pasted directly into the COF or the inbox
- if (!isCOFFolder() && !isInboxFolder())
+ if (!is_cof && !is_inbox)
{
items.push_back(std::string("Paste"));
}
@@ -1334,6 +1352,13 @@ bool LLInvFVBridge::isAgentInventory() const
return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
}
+bool LLInvFVBridge::isAgentInventoryRoot() const
+{
+ const LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+ return gInventory.getRootFolderID() == mUUID;
+}
+
bool LLInvFVBridge::isCOFFolder() const
{
return LLAppearanceMgr::instance().getIsInCOF(mUUID);
@@ -2281,6 +2306,21 @@ const LLUUID& LLItemBridge::getThumbnailUUID() const
return LLUUID::null;
}
+bool LLItemBridge::isFavorite() const
+{
+ LLViewerInventoryItem* item = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if (model)
+ {
+ item = model->getItem(mUUID);
+ }
+ if (item)
+ {
+ return get_is_favorite(item);
+ }
+ return false;
+}
+
// virtual
bool LLItemBridge::isItemPermissive() const
{
@@ -2426,6 +2466,16 @@ const LLUUID& LLFolderBridge::getThumbnailUUID() const
return LLUUID::null;
}
+bool LLFolderBridge::isFavorite() const
+{
+ LLViewerInventoryCategory* cat = getCategory();
+ if (cat)
+ {
+ return cat->getIsFavorite();
+ }
+ return false;
+}
+
void LLFolderBridge::update()
{
// we know we have children but haven't fetched them (doesn't obey filter)
@@ -4189,6 +4239,32 @@ void LLFolderBridge::pasteLinkFromClipboard()
std::vector<LLUUID> objects;
LLClipboard::instance().pasteFromClipboard(objects);
+ if (objects.size() == 0)
+ {
+ LLClipboard::instance().setCutMode(false);
+ return;
+ }
+
+ LLUUID& first_id = objects[0];
+ LLInventoryItem* item = model->getItem(first_id);
+ if (item && item->getAssetUUID().isNull())
+ {
+ if (item->getActualType() == LLAssetType::AT_NOTECARD)
+ {
+ // otehrwise AIS will return 'Cannot link to items with a NULL asset_id.'
+ LLNotificationsUtil::add("CantLinkNotecard");
+ LLClipboard::instance().setCutMode(false);
+ return;
+ }
+ else if (item->getActualType() == LLAssetType::AT_MATERIAL)
+ {
+ LLNotificationsUtil::add("CantLinkMaterial");
+ LLClipboard::instance().setCutMode(false);
+ return;
+ }
+ }
+
+
LLPointer<LLInventoryCallback> cb = NULL;
LLInventoryPanel* panel = mInventoryPanel.get();
if (panel->getRootFolder()->isSingleFolderMode())
@@ -4272,6 +4348,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
}
disabled_items.push_back(std::string("New Folder"));
+ disabled_items.push_back(std::string("upload_options"));
disabled_items.push_back(std::string("upload_def"));
disabled_items.push_back(std::string("create_new"));
}
@@ -4297,6 +4374,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
{
disabled_items.push_back(std::string("New Folder"));
disabled_items.push_back(std::string("New Listing Folder"));
+ disabled_items.push_back(std::string("upload_options"));
disabled_items.push_back(std::string("upload_def"));
disabled_items.push_back(std::string("create_new"));
}
@@ -4363,6 +4441,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
}
if (!isMarketplaceListingsFolder())
{
+ items.push_back(std::string("upload_options"));
items.push_back(std::string("upload_def"));
items.push_back(std::string("create_new"));
items.push_back(std::string("New Script"));
@@ -4396,6 +4475,15 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
items.push_back(std::string("Rename"));
items.push_back(std::string("thumbnail"));
+ if (cat->getIsFavorite())
+ {
+ items.push_back(std::string("Remove from Favorites"));
+ }
+ else
+ {
+ items.push_back(std::string("Add to Favorites"));
+ }
+
addDeleteContextMenuOptions(items, disabled_items);
// EXT-4030: disallow deletion of currently worn outfit
const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
@@ -6905,7 +6993,7 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
else if(item && item->isFinished())
{
// must be in library. copy it to our inventory and put it on.
- LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0));
+ LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, true));
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
@@ -8030,7 +8118,8 @@ void LLObjectBridgeAction::attachOrDetach()
}
else
{
- LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding.
+ static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryAddAttachmentBehavior", false);
+ LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, inventory_linking()); // Don't replace if adding.
}
}
@@ -8221,6 +8310,7 @@ void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
buildContextMenuOptions(flags, items, disabled_items);
items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end());
+ items.erase(std::remove(items.begin(), items.end(), std::string("New folder from selected")), items.end());
hide_context_entries(menu, items, disabled_items);
}
@@ -8255,6 +8345,51 @@ LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge(
return new_listener;
}
+/************************************************************************/
+/* Favorites Inventory Panel related classes */
+/************************************************************************/
+void LLFavoritesFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ // todo: consider things that should be disabled
+ menuentry_vec_t disabled_items, items;
+ buildContextMenuOptions(flags, items, disabled_items);
+
+ items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end());
+ items.erase(std::remove(items.begin(), items.end(), std::string("New folder from selected")), items.end());
+
+ hide_context_entries(menu, items, disabled_items);
+}
+
+LLInvFVBridge* LLFavoritesInventoryBridgeBuilder::createBridge(
+ LLAssetType::EType asset_type,
+ LLAssetType::EType actual_asset_type,
+ LLInventoryType::EType inv_type,
+ LLInventoryPanel* inventory,
+ LLFolderViewModelInventory* view_model,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags /*= 0x00*/) const
+{
+ LLInvFVBridge* new_listener = NULL;
+ if (asset_type == LLAssetType::AT_CATEGORY
+ && actual_asset_type != LLAssetType::AT_LINK_FOLDER)
+ {
+ new_listener = new LLFavoritesFolderBridge(inv_type, inventory, root, uuid);
+ }
+ else
+ {
+ new_listener = LLInventoryFolderViewModelBuilder::createBridge(asset_type,
+ actual_asset_type,
+ inv_type,
+ inventory,
+ view_model,
+ root,
+ uuid,
+ flags);
+ }
+ return new_listener;
+}
+
LLFolderViewGroupedItemBridge::LLFolderViewGroupedItemBridge()
{
}
@@ -8265,7 +8400,7 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ
menuentry_vec_t disabled_items;
if (get_selection_item_uuids(selected_items, ids))
{
- if (!LLAppearanceMgr::instance().canAddWearables(ids) && canWearSelected(ids))
+ if (!LLAppearanceMgr::instance().canAddWearables(ids, false) && canWearSelected(ids))
{
disabled_items.push_back(std::string("Wearable And Object Wear"));
disabled_items.push_back(std::string("Wearable Add"));
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 3e7f74384b..1b80ac163c 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -86,6 +86,7 @@ public:
//--------------------------------------------------------------------
virtual const LLUUID& getUUID() const { return mUUID; }
virtual const LLUUID& getThumbnailUUID() const { return LLUUID::null; }
+ virtual bool isFavorite() const { return false; }
virtual void clearDisplayName() { mDisplayName.clear(); }
virtual void restoreItem() {}
virtual void restoreToWorld() {}
@@ -175,6 +176,7 @@ protected:
bool isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory?
bool isAgentInventory() const; // false if lost or in the inventory library
+ bool isAgentInventoryRoot() const; // true if worn by agent
bool isCOFFolder() const; // true if COF or descendant of
bool isInboxFolder() const; // true if COF or descendant of marketplace inbox
@@ -259,6 +261,7 @@ public:
LLViewerInventoryItem* getItem() const;
virtual const LLUUID& getThumbnailUUID() const;
+ virtual bool isFavorite() const;
protected:
bool confirmRemoveItem(const LLSD& notification, const LLSD& response);
@@ -301,6 +304,7 @@ public:
virtual std::string getLabelSuffix() const;
virtual LLFontGL::StyleFlags getLabelStyle() const;
virtual const LLUUID& getThumbnailUUID() const;
+ virtual bool isFavorite() const;
void setShowDescendantsCount(bool show_count) {mShowDescendantsCount = show_count;}
@@ -754,6 +758,45 @@ public:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Favorites Inventory Panel related classes
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// Overridden version of the Inventory-Folder-View-Bridge for Folders
+class LLFavoritesFolderBridge : public LLFolderBridge
+{
+ friend class LLInvFVBridgeAction;
+public:
+ // Creates context menu for Folders related to Recent Inventory Panel.
+ // Uses base logic and than removes from visible items "New..." menu items.
+ LLFavoritesFolderBridge(LLInventoryType::EType type,
+ LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ LLFolderBridge(inventory, root, uuid)
+ {
+ mInvType = type;
+ }
+ /*virtual*/ void buildContextMenu(LLMenuGL& menu, U32 flags);
+};
+
+// Bridge builder to create Inventory-Folder-View-Bridge for Recent Inventory Panel
+class LLFavoritesInventoryBridgeBuilder : public LLInventoryFolderViewModelBuilder
+{
+public:
+ LLFavoritesInventoryBridgeBuilder() {}
+ // Overrides FolderBridge for Recent Inventory Panel.
+ // It use base functionality for bridges other than FolderBridge.
+ virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type,
+ LLAssetType::EType actual_asset_type,
+ LLInventoryType::EType inv_type,
+ LLInventoryPanel* inventory,
+ LLFolderViewModelInventory* view_model,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags = 0x00) const;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Marketplace Inventory Panel related classes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -780,7 +823,7 @@ private:
void rez_attachment(LLViewerInventoryItem* item,
LLViewerJointAttachment* attachment,
- bool replace = false);
+ bool replace);
// Move items from an in-world object's "Contents" folder to a specified
// folder in agent inventory.
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index 5c0905af3c..99c2d6e410 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -64,6 +64,7 @@ LLInventoryFilter::FilterOps::FilterOps(const Params& p)
mFilterUUID(p.uuid),
mFilterLinks(p.links),
mFilterThumbnails(p.thumbnails),
+ mFilterFavorites(p.favorites),
mSearchVisibility(p.search_visibility)
{
}
@@ -159,6 +160,7 @@ bool LLInventoryFilter::check(const LLFolderViewModelItem* item)
passed = passed && checkAgainstCreator(listener);
passed = passed && checkAgainstSearchVisibility(listener);
+ passed = passed && checkAgainstFilterFavorites(listener->getUUID());
passed = passed && checkAgainstFilterThumbnails(listener->getUUID());
return passed;
@@ -221,6 +223,19 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
return false;
}
+ const LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
+ if (cat && cat->getIsFavorite())
+ {
+ if (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES)
+ {
+ return true;
+ }
+ if (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES)
+ {
+ return false;
+ }
+ }
+
// Marketplace folder filtering
const U32 filterTypes = mFilterOps.mFilterTypes;
const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE |
@@ -273,6 +288,16 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
}
}
+ if (filterTypes & FILTERTYPE_NO_TRASH_ITEMS)
+ {
+ const LLUUID trash_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ // If not a descendant of the marketplace listings root, then the nesting depth is -1 by definition
+ if (gInventory.isObjectDescendentOf(folder_id, trash_uuid))
+ {
+ return false;
+ }
+ }
+
// show folder links
LLViewerInventoryItem* item = gInventory.getItem(folder_id);
if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER)
@@ -611,6 +636,24 @@ bool LLInventoryFilter::checkAgainstFilterThumbnails(const LLUUID& object_id) co
return true;
}
+bool LLInventoryFilter::checkAgainstFilterFavorites(const LLUUID& object_id) const
+{
+ const LLInventoryObject* object = gInventory.getObject(object_id);
+ if (!object) return true;
+
+
+ if (mFilterOps.mFilterFavorites != FILTER_INCLUDE_FAVORITES)
+ {
+ bool is_favorite = get_is_favorite(object);
+ if (is_favorite && (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES))
+ return false;
+ if (!is_favorite && (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES))
+ return false;
+ }
+
+ return true;
+}
+
bool LLInventoryFilter::checkAgainstCreator(const LLFolderViewModelItemInventory* listener) const
{
if (!listener)
@@ -811,6 +854,32 @@ void LLInventoryFilter::setFilterThumbnails(U64 filter_thumbnails)
mFilterOps.mFilterThumbnails = filter_thumbnails;
}
+void LLInventoryFilter::setFilterFavorites(U64 filter_favorites)
+{
+ if (mFilterOps.mFilterFavorites != filter_favorites)
+ {
+ if (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES
+ && filter_favorites == FILTER_ONLY_FAVORITES)
+ {
+ setModified(FILTER_RESTART);
+ }
+ else if (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES
+ && filter_favorites == FILTER_EXCLUDE_FAVORITES)
+ {
+ setModified(FILTER_RESTART);
+ }
+ else if (mFilterOps.mFilterFavorites == FILTER_INCLUDE_FAVORITES)
+ {
+ setModified(FILTER_MORE_RESTRICTIVE);
+ }
+ else
+ {
+ setModified(FILTER_LESS_RESTRICTIVE);
+ }
+ }
+ mFilterOps.mFilterFavorites = filter_favorites;
+}
+
void LLInventoryFilter::setFilterEmptySystemFolders()
{
mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS;
@@ -923,6 +992,11 @@ void LLInventoryFilter::toggleSearchVisibilityLibrary()
}
}
+void LLInventoryFilter::setFilterNoTrashFolder()
+{
+ mFilterOps.mFilterTypes |= FILTERTYPE_NO_TRASH_ITEMS;
+}
+
void LLInventoryFilter::setFilterNoMarketplaceFolder()
{
mFilterOps.mFilterTypes |= FILTERTYPE_NO_MARKETPLACE_ITEMS;
@@ -959,7 +1033,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string)
boost::char_separator<char> sep("+");
tokenizer tokens(filter_sub_string_new, sep);
- for (auto token_iter : tokens)
+ for (const auto& token_iter : tokens)
{
mFilterTokens.push_back(token_iter);
}
@@ -1025,7 +1099,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string)
}
// Cancel out UUID once the search string is modified
- if (mFilterOps.mFilterTypes == FILTERTYPE_UUID)
+ if (mFilterOps.mFilterTypes & FILTERTYPE_UUID)
{
mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID;
mFilterOps.mFilterUUID = LLUUID::null;
@@ -1615,6 +1689,11 @@ U64 LLInventoryFilter::getFilterThumbnails() const
return mFilterOps.mFilterThumbnails;
}
+U64 LLInventoryFilter::getFilterFavorites() const
+{
+ return mFilterOps.mFilterFavorites;
+}
+
bool LLInventoryFilter::hasFilterString() const
{
return mFilterSubString.size() > 0;
@@ -1707,7 +1786,7 @@ std::string LLInventoryFilter::getEmptyLookupMessage(bool is_empty_folder) const
}
}
-bool LLInventoryFilter::areDateLimitsSet()
+bool LLInventoryFilter::areDateLimitsSet() const
{
return mFilterOps.mMinDate != time_min()
|| mFilterOps.mMaxDate != time_max()
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index 7e64a03e73..c0164e04e4 100644
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -61,6 +61,7 @@ public:
FILTERTYPE_NO_MARKETPLACE_ITEMS = 0x1 << 10, // pass iff folder is not under the marketplace
FILTERTYPE_WORN = 0x1 << 11, // pass if item is worn
FILTERTYPE_SETTINGS = 0x1 << 12, // pass if the item is a settings object
+ FILTERTYPE_NO_TRASH_ITEMS = 0x1 << 13, // pass iff folder is not under the marketplace
};
enum EFilterDateDirection
@@ -83,6 +84,13 @@ public:
FILTER_ONLY_THUMBNAILS
};
+ enum EFilterFavorite
+ {
+ FILTER_INCLUDE_FAVORITES,
+ FILTER_EXCLUDE_FAVORITES,
+ FILTER_ONLY_FAVORITES
+ };
+
enum ESortOrderType
{
SO_NAME = 0, // Sort inventory by name
@@ -149,6 +157,7 @@ public:
Optional<PermissionMask> permissions;
Optional<EFilterCreatorType> creator_type;
Optional<EFilterThumbnail> thumbnails;
+ Optional<EFilterFavorite> favorites;
Params()
: types("filter_types", FILTERTYPE_OBJECT),
@@ -156,6 +165,7 @@ public:
wearable_types("wearable_types", 0xffffFFFFffffFFFFULL),
settings_types("settings_types", 0xffffFFFFffffFFFFULL),
thumbnails("thumbnails", FILTER_INCLUDE_THUMBNAILS),
+ favorites("favorites", FILTER_INCLUDE_FAVORITES),
category_types("category_types", 0xffffFFFFffffFFFFULL),
links("links", FILTERLINK_INCLUDE_LINKS),
search_visibility("search_visibility", 0xFFFFFFFF),
@@ -177,6 +187,7 @@ public:
mFilterWearableTypes,
mFilterSettingsTypes, // for _SETTINGS
mFilterThumbnails,
+ mFilterFavorites,
mFilterLinks,
mFilterCategoryTypes; // For _CATEGORY
LLUUID mFilterUUID; // for UUID
@@ -220,6 +231,7 @@ public:
U64 getFilterSettingsTypes() const;
U64 getSearchVisibilityTypes() const;
U64 getFilterThumbnails() const;
+ U64 getFilterFavorites() const;
bool isFilterObjectTypesWith(LLInventoryType::EType t) const;
void setFilterObjectTypes(U64 types);
@@ -233,8 +245,10 @@ public:
void setFilterMarketplaceInactiveFolders();
void setFilterMarketplaceUnassociatedFolders();
void setFilterMarketplaceListingFolders(bool select_only_listing_folders);
+ void setFilterNoTrashFolder();
void setFilterNoMarketplaceFolder();
void setFilterThumbnails(U64 filter_thumbnails);
+ void setFilterFavorites(U64 filter_favorites);
void updateFilterTypes(U64 types, U64& current_types);
void setSearchType(ESearchType type);
ESearchType getSearchType() { return mSearchType; }
@@ -339,9 +353,10 @@ public:
LLInventoryFilter& operator =(const LLInventoryFilter& other);
bool checkAgainstFilterThumbnails(const LLUUID& object_id) const;
+ bool checkAgainstFilterFavorites(const LLUUID& object_id) const;
private:
- bool areDateLimitsSet();
+ bool areDateLimitsSet() const;
bool checkAgainstFilterSubString(const std::string& desc) const;
bool checkAgainstFilterType(const class LLFolderViewModelItemInventory* listener) const;
bool checkAgainstFilterType(const LLInventoryItem* item) const;
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index dadd0590a9..2be6a91bbf 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -51,6 +51,7 @@
#include "lldirpicker.h"
#include "lldonotdisturbnotificationstorage.h"
#include "llfloatermarketplacelistings.h"
+#include "llfloatermodelpreview.h"
#include "llfloatersidepanelcontainer.h"
#include "llfocusmgr.h"
#include "llfolderview.h"
@@ -62,6 +63,7 @@
#include "llinventorymodel.h"
#include "llinventorypanel.h"
#include "lllineeditor.h"
+#include "llmaterialeditor.h"
#include "llmarketplacenotifications.h"
#include "llmarketplacefunctions.h"
#include "llmenugl.h"
@@ -86,6 +88,7 @@
#include "llviewermessage.h"
#include "llviewerfoldertype.h"
#include "llviewerobjectlist.h"
+#include "llviewermenufile.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "llvoavatarself.h"
@@ -2418,6 +2421,149 @@ void ungroup_folder_items(const LLUUID& folder_id)
gInventory.notifyObservers();
}
+class LLUpdateFavorite : public LLInventoryCallback
+{
+public:
+ LLUpdateFavorite(const LLUUID& inv_item_id)
+ : mInvItemID(inv_item_id)
+ {}
+ /* virtual */ void fire(const LLUUID& inv_item_id) override
+ {
+ gInventory.addChangedMask(LLInventoryObserver::UPDATE_FAVORITE, mInvItemID);
+
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::cat_array_t cat_array;
+ LLLinkedItemIDMatches matches(mInvItemID);
+ gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
+ cat_array,
+ items,
+ LLInventoryModel::INCLUDE_TRASH,
+ matches);
+
+ std::set<LLUUID> link_ids;
+ for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it)
+ {
+ LLPointer<LLViewerInventoryItem> item = *it;
+
+ gInventory.addChangedMask(LLInventoryObserver::UPDATE_FAVORITE, item->getUUID());
+ }
+
+ gInventory.notifyObservers();
+ }
+private:
+ LLUUID mInvItemID;
+};
+
+void favorite_send(LLInventoryObject* obj, const LLUUID& obj_id, bool favorite)
+ {
+ LLSD val;
+ if (favorite)
+ {
+ val = true;
+ } // else leave undefined to remove unneeded metadata field
+
+ LLSD updates;
+ if (favorite)
+ {
+ updates["favorite"] = LLSD().with("toggled", true);
+ }
+ else
+ {
+ updates["favorite"] = LLSD();
+ }
+
+ LLPointer<LLInventoryCallback> cb = new LLUpdateFavorite(obj_id);
+
+ LLViewerInventoryCategory* view_folder = dynamic_cast<LLViewerInventoryCategory*>(obj);
+ if (view_folder)
+ {
+ update_inventory_category(obj_id, updates, cb);
+ }
+ LLViewerInventoryItem* view_item = dynamic_cast<LLViewerInventoryItem*>(obj);
+ if (view_item)
+ {
+ update_inventory_item(obj_id, updates, cb);
+ }
+ }
+
+bool get_is_favorite(const LLInventoryObject* object)
+{
+ if (object->getIsLinkType())
+ {
+ LLInventoryObject* obj = gInventory.getObject(object->getLinkedUUID());
+ return obj && obj->getIsFavorite();
+ }
+
+ return object->getIsFavorite();
+}
+
+bool get_is_favorite(const LLUUID& obj_id)
+{
+ LLInventoryObject* object = gInventory.getObject(obj_id);
+ if (object && object->getIsLinkType())
+ {
+ LLInventoryObject* obj = gInventory.getObject(object->getLinkedUUID());
+ return obj && obj->getIsFavorite();
+ }
+
+ return object->getIsFavorite();
+}
+
+void set_favorite(const LLUUID& obj_id, bool favorite)
+{
+ LLInventoryObject* obj = gInventory.getObject(obj_id);
+
+ if (obj && obj->getIsLinkType())
+ {
+ if (!favorite && obj->getIsFavorite())
+ {
+ // Links currently aren't supposed to be favorites,
+ // instead should show state of the original
+ LL_INFOS("Inventory") << "Recovering proper 'favorites' state of a link " << obj_id << LL_ENDL;
+ favorite_send(obj, obj_id, false);
+ }
+ obj = gInventory.getObject(obj->getLinkedUUID());
+ }
+
+ if (obj && obj->getIsFavorite() != favorite)
+ {
+ favorite_send(obj, obj->getUUID(), favorite);
+ }
+}
+
+void toggle_favorite(const LLUUID& obj_id)
+{
+ LLInventoryObject* obj = gInventory.getObject(obj_id);
+ if (obj && obj->getIsLinkType())
+ {
+ obj = gInventory.getObject(obj->getLinkedUUID());
+ }
+
+ if (obj)
+ {
+ favorite_send(obj, obj->getUUID(), !obj->getIsFavorite());
+ }
+}
+
+void toggle_favorites(const uuid_vec_t& ids)
+{
+ if (ids.size() == 0)
+ {
+ return;
+ }
+ if (ids.size() == 1)
+ {
+ toggle_favorite(ids[0]);
+ return;
+ }
+
+ bool new_val = !get_is_favorite(ids.front());
+ for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ set_favorite(*it, new_val);
+ }
+}
+
std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id)
{
if (model)
@@ -2697,6 +2843,20 @@ bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryIt
return false;
}
+bool LLFavoritesCollector::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ if (item && item->getIsFavorite())
+ {
+ return true;
+ }
+ if (cat && cat->getIsFavorite())
+ {
+ return true;
+ }
+ return false;
+}
+
bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
@@ -2758,6 +2918,19 @@ bool LLNameCategoryCollector::operator()(
return false;
}
+bool LLNameItemCollector::operator()(
+ LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ if(item)
+ {
+ if (!LLStringUtil::compareInsensitive(mName, item->getName()))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
@@ -3181,7 +3354,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
for (LLInventoryModel::item_array_t::value_type& item : items)
{
- if (get_is_item_worn(item))
+ if (!item->getIsLinkType() && get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
@@ -3201,7 +3374,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
}
}
LLViewerInventoryItem* item = gInventory.getItem(obj_id);
- if (item && get_is_item_worn(item))
+ if (item && !item->getIsLinkType() && get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
@@ -3468,6 +3641,20 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
LLFloaterReg::showInstance("change_item_thumbnail", data);
}
}
+ else if ("add_to_favorites" == action)
+ {
+ for (const LLUUID& id : ids)
+ {
+ set_favorite(id, true);
+ }
+ }
+ else if ("remove_from_favorites" == action)
+ {
+ for (const LLUUID& id : ids)
+ {
+ set_favorite(id, false);
+ }
+ }
else
{
std::set<LLFolderViewItem*>::iterator set_iter;
@@ -3561,6 +3748,54 @@ void LLInventoryAction::removeItemFromDND(LLFolderView* root)
}
}
+void LLInventoryAction::fileUploadLocation(const LLUUID& dest_id, const std::string& action)
+{
+ if (action == "def_model")
+ {
+ gSavedPerAccountSettings.setString("ModelUploadFolder", dest_id.asString());
+ }
+ else if (action == "def_texture")
+ {
+ gSavedPerAccountSettings.setString("TextureUploadFolder", dest_id.asString());
+ }
+ else if (action == "def_sound")
+ {
+ gSavedPerAccountSettings.setString("SoundUploadFolder", dest_id.asString());
+ }
+ else if (action == "def_animation")
+ {
+ gSavedPerAccountSettings.setString("AnimationUploadFolder", dest_id.asString());
+ }
+ else if (action == "def_pbr_material")
+ {
+ gSavedPerAccountSettings.setString("PBRUploadFolder", dest_id.asString());
+ }
+ else if (action == "upload_texture")
+ {
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_IMAGE, false);
+ }
+ else if (action == "upload_sound")
+ {
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_WAV, false);
+ }
+ else if (action == "upload_animation")
+ {
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_ANIM, false);
+ }
+ else if (action == "upload_model")
+ {
+ LLFloaterModelPreview::showModelPreview(dest_id);
+ }
+ else if (action == "upload_pbr_material")
+ {
+ LLMaterialEditor::importMaterial(dest_id);
+ }
+ else if (action == "upload_bulk")
+ {
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2, true, dest_id), LLFilePicker::FFLOAD_ALL, true);
+ }
+}
+
void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index a25c0d5ad6..9e2739ef29 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -116,6 +116,11 @@ bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_ca
std::string get_localized_folder_name(LLUUID cat_uuid);
void new_folder_window(const LLUUID& folder_id);
void ungroup_folder_items(const LLUUID& folder_id);
+bool get_is_favorite(const LLInventoryObject* object);
+bool get_is_favorite(const LLUUID& obj_id);
+void set_favorite(const LLUUID& obj_id, bool favorite);
+void toggle_favorite(const LLUUID& obj_id);
+void toggle_favorites(const uuid_vec_t& ids);
std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id);
std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id);
std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id);
@@ -189,6 +194,8 @@ public:
virtual ~LLInventoryCollectFunctor(){};
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0;
+ virtual bool exceedsLimit() { return false; }
+
static bool itemTransferCommonlyAllowed(const LLInventoryItem* item);
};
@@ -326,6 +333,18 @@ protected:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLFavoritesCollector
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLFavoritesCollector : public LLInventoryCollectFunctor
+{
+public:
+ LLFavoritesCollector() {}
+ virtual ~LLFavoritesCollector() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLBuddyCollector
//
// Simple class that collects calling cards that are not null, and not
@@ -392,6 +411,22 @@ protected:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLNameItemCollector
+//
+// Collects items based on case-insensitive match of prefix
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLNameItemCollector : public LLInventoryCollectFunctor
+{
+public:
+ LLNameItemCollector(const std::string& name) : mName(name) {}
+ virtual ~LLNameItemCollector() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+protected:
+ std::string mName;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFindCOFValidItems
//
// Collects items that can be legitimately linked to in the COF.
@@ -583,6 +618,7 @@ struct LLInventoryAction
static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action);
static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root);
static void removeItemFromDND(LLFolderView* root);
+ static void fileUploadLocation(const LLUUID& dest_id, const std::string& action);
static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model);
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
index c4f93cee98..93f5425fd7 100644
--- a/indra/newview/llinventorygallery.cpp
+++ b/indra/newview/llinventorygallery.cpp
@@ -634,7 +634,7 @@ void LLInventoryGallery::removeFromLastRow(LLInventoryGalleryItem* item)
mItemPanels.pop_back();
}
-LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn)
+LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn, bool is_favorite)
{
LLInventoryGalleryItem::Params giparams;
giparams.visible = true;
@@ -645,6 +645,7 @@ LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, L
gitem->setUUID(item_id);
gitem->setGallery(this);
gitem->setType(type, inventory_type, flags, is_link);
+ gitem->setFavorite(is_favorite);
gitem->setLoadImmediately(mLoadThumbnailsImmediately);
gitem->setThumbnail(thumbnail_id);
gitem->setWorn(is_worn);
@@ -937,8 +938,19 @@ bool LLInventoryGallery::updateAddedItem(LLUUID item_id)
}
bool res = false;
-
- LLInventoryGalleryItem* item = buildGalleryItem(name, item_id, obj->getType(), thumbnail_id, inventory_type, misc_flags, obj->getCreationDate(), obj->getIsLinkType(), is_worn);
+ bool is_favorite = get_is_favorite(obj);
+
+ LLInventoryGalleryItem* item = buildGalleryItem(
+ name,
+ item_id,
+ obj->getType(),
+ thumbnail_id,
+ inventory_type,
+ misc_flags,
+ obj->getCreationDate(),
+ obj->getIsLinkType(),
+ is_worn,
+ is_favorite);
mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item));
if (mGalleryCreated)
{
@@ -975,7 +987,7 @@ void LLInventoryGallery::updateRemovedItem(LLUUID item_id)
mItemBuildQuery.erase(item_id);
}
-void LLInventoryGallery::updateChangedItemName(LLUUID item_id, std::string name)
+void LLInventoryGallery::updateChangedItemData(LLUUID item_id, std::string name, bool is_favorite)
{
gallery_item_map_t::iterator iter = mItemMap.find(item_id);
if (iter != mItemMap.end())
@@ -984,6 +996,7 @@ void LLInventoryGallery::updateChangedItemName(LLUUID item_id, std::string name)
if (item)
{
item->setItemName(name);
+ item->setFavorite(is_favorite);
}
}
}
@@ -1999,7 +2012,7 @@ void LLInventoryGallery::deleteSelection()
for (LLInventoryModel::item_array_t::value_type& item : items)
{
- if (get_is_item_worn(item))
+ if (!item->getIsLinkType() && get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
@@ -2020,7 +2033,7 @@ void LLInventoryGallery::deleteSelection()
}
LLViewerInventoryItem* item = gInventory.getItem(id);
- if (item && get_is_item_worn(item))
+ if (item && !item->getIsLinkType() && get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
@@ -2105,6 +2118,30 @@ void LLInventoryGallery::pasteAsLink()
std::vector<LLUUID> objects;
LLClipboard::instance().pasteFromClipboard(objects);
+ if (objects.size() == 0)
+ {
+ LLClipboard::instance().setCutMode(false);
+ return;
+ }
+
+ LLUUID& first_id = objects[0];
+ LLInventoryItem* item = gInventory.getItem(first_id);
+ if (item && item->getAssetUUID().isNull())
+ {
+ if (item->getActualType() == LLAssetType::AT_NOTECARD)
+ {
+ LLNotificationsUtil::add("CantLinkNotecard");
+ LLClipboard::instance().setCutMode(false);
+ return;
+ }
+ else if (item->getActualType() == LLAssetType::AT_MATERIAL)
+ {
+ LLNotificationsUtil::add("CantLinkMaterial");
+ LLClipboard::instance().setCutMode(false);
+ return;
+ }
+ }
+
bool paste_into_root = mSelectedItemIDs.empty();
for (LLUUID& dest : mSelectedItemIDs)
{
@@ -2333,7 +2370,7 @@ void LLInventoryGallery::refreshList(const LLUUID& category_id)
return;
}
- updateChangedItemName(*items_iter, obj->getName());
+ updateChangedItemData(*items_iter, obj->getName(), get_is_favorite(obj));
mNeedsArrange = true;
}
@@ -2849,6 +2886,14 @@ void LLInventoryGalleryItem::setType(LLAssetType::EType type, LLInventoryType::E
getChild<LLIconCtrl>("link_overlay")->setVisible(is_link);
}
+void LLInventoryGalleryItem::setFavorite(bool is_favorite)
+{
+ getChild<LLIconCtrl>("fav_icon")->setVisible(is_favorite);
+ static const LLUIColor text_color = LLUIColorTable::instance().getColor("LabelTextColor", LLColor4::white);
+ static const LLUIColor favorite_color = LLUIColorTable::instance().getColor("InventoryFavoriteColor", LLColor4::white);
+ mNameText->setReadOnlyColor(is_favorite ? favorite_color : text_color);
+}
+
void LLInventoryGalleryItem::setThumbnail(LLUUID id)
{
mDefaultImage = id.isNull();
diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h
index 59d08d19ed..7f53f9998d 100644
--- a/indra/newview/llinventorygallery.h
+++ b/indra/newview/llinventorygallery.h
@@ -102,7 +102,7 @@ public:
void getCurrentCategories(uuid_vec_t& vcur);
bool updateAddedItem(LLUUID item_id); // returns true if added item is visible
void updateRemovedItem(LLUUID item_id);
- void updateChangedItemName(LLUUID item_id, std::string name);
+ void updateChangedItemData(LLUUID item_id, std::string name, bool is_favorite);
void updateItemThumbnail(LLUUID item_id);
void updateWornItem(LLUUID item_id, bool is_worn);
@@ -227,7 +227,7 @@ private:
bool updateRowsIfNeeded();
void updateGalleryWidth();
- LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn);
+ LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn, bool is_favorite);
LLInventoryGalleryItem* getItem(const LLUUID& id) const;
void buildGalleryPanel(int row_count);
@@ -343,6 +343,7 @@ public:
void setHidden(bool hidden) {mHidden = hidden;}
void setType(LLAssetType::EType type, LLInventoryType::EType inventory_type, U32 flags, bool is_link);
+ void setFavorite(bool is_favorite);
LLAssetType::EType getAssetType() { return mType; }
void setThumbnail(LLUUID id);
void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }
diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp
index 0c35a7f695..d03604d079 100644
--- a/indra/newview/llinventorygallerymenu.cpp
+++ b/indra/newview/llinventorygallerymenu.cpp
@@ -87,14 +87,15 @@ void modify_outfit(bool append, const LLUUID& cat_id, LLInventoryModel* model)
LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
- registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2));
- registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2));
- registrar.add("Inventory.SetFavoriteFolder", boost::bind(&LLInventoryGalleryContextMenu::setFavoriteFolder, this));
- registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
- registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
+ registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Inventory.EmptyTrash",
+ boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Inventory.EmptyLostAndFound",
+ boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
registrar.add("Inventory.DoCreate", [this](LLUICtrl*, const LLSD& data)
{
if (mRootFolder)
@@ -105,10 +106,11 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
{
mGallery->doCreate(mUUIDs.front(), data);
}
- });
+ },
+ LLUICtrl::cb_info::UNTRUSTED_BLOCK);
std::set<LLUUID> uuids(mUUIDs.begin(), mUUIDs.end());
- registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
+ registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2));
enable_registrar.add("Inventory.CanSetFavoriteFolder", boost::bind(&LLInventoryGalleryContextMenu::canSetFavoriteFolder, this));
@@ -268,6 +270,20 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)
LLAppearanceMgr::instance().takeOffOutfit(cat->getLinkedUUID());
}
}
+ else if ("add_to_favorites" == action)
+ {
+ for (const LLUUID& id : mUUIDs)
+ {
+ set_favorite(id, true);
+ }
+ }
+ else if ("remove_from_favorites" == action)
+ {
+ for (const LLUUID& id : mUUIDs)
+ {
+ set_favorite(id, false);
+ }
+ }
else if ("take_off" == action || "detach" == action)
{
for (LLUUID& selected_id : mUUIDs)
@@ -474,22 +490,7 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS
void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata)
{
const std::string param = userdata.asString();
- if (param == "model")
- {
- gSavedPerAccountSettings.setString("ModelUploadFolder", mUUIDs.front().asString());
- }
- else if (param == "texture")
- {
- gSavedPerAccountSettings.setString("TextureUploadFolder", mUUIDs.front().asString());
- }
- else if (param == "sound")
- {
- gSavedPerAccountSettings.setString("SoundUploadFolder", mUUIDs.front().asString());
- }
- else if (param == "animation")
- {
- gSavedPerAccountSettings.setString("AnimationUploadFolder", mUUIDs.front().asString());
- }
+ LLInventoryAction::fileUploadLocation(mUUIDs.front(), param);
}
bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata)
@@ -616,20 +617,23 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
bool has_children = false;
bool is_full_perm_item = false;
bool is_copyable = false;
- LLViewerInventoryItem* selected_item = gInventory.getItem(selected_id);
+
+ LLViewerInventoryCategory* selected_category = nullptr;
+ LLViewerInventoryItem* selected_item = nullptr;
if(is_folder)
{
- LLInventoryCategory* category = gInventory.getCategory(selected_id);
- if (category)
+ selected_category = dynamic_cast<LLViewerInventoryCategory*>(obj);
+ if (selected_category)
{
- folder_type = category->getPreferredType();
+ folder_type = selected_category->getPreferredType();
is_system_folder = LLFolderType::lookupIsProtectedType(folder_type);
has_children = (gInventory.categoryHasChildren(selected_id) != LLInventoryModel::CHILDREN_NO);
}
}
else
{
+ selected_item = dynamic_cast<LLViewerInventoryItem*>(obj);
if (selected_item)
{
is_full_perm_item = selected_item->getIsFullPerm();
@@ -748,8 +752,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
{
if (is_agent_inventory && !is_inbox && !is_cof && !is_in_favorites && !is_outfits)
{
- LLViewerInventoryCategory* category = gInventory.getCategory(selected_id);
- if (!category || !LLFriendCardsManager::instance().isCategoryInFriendFolder(category))
+ if (!selected_category || !LLFriendCardsManager::instance().isCategoryInFriendFolder(selected_category))
{
items.push_back(std::string("New Folder"));
}
@@ -777,6 +780,22 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
if (inventory_linking)
{
items.push_back(std::string("Paste As Link"));
+
+ if (selected_item)
+ {
+ if (!LLAssetType::lookupCanLink(selected_item->getActualType()))
+ {
+ disabled_items.push_back(std::string("Paste As Link"));
+ }
+ else if (gInventory.isObjectDescendentOf(selected_item->getUUID(), gInventory.getLibraryRootFolderID()))
+ {
+ disabled_items.push_back(std::string("Paste As Link"));
+ }
+ }
+ else if (selected_category && LLFolderType::lookupIsProtectedType(selected_category->getPreferredType()))
+ {
+ disabled_items.push_back(std::string("Paste As Link"));
+ }
}
}
if (is_folder && is_agent_inventory)
@@ -787,6 +806,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
{
items.push_back(std::string("New Folder"));
}
+ items.push_back(std::string("upload_options"));
items.push_back(std::string("upload_def"));
}
@@ -797,6 +817,18 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
items.push_back(std::string("New Outfit"));
}
+ if (!is_trash && !is_in_trash && gInventory.getRootFolderID() != selected_id)
+ {
+ if (get_is_favorite(obj))
+ {
+ items.push_back(std::string("Remove from Favorites"));
+ }
+ else
+ {
+ items.push_back(std::string("Add to Favorites"));
+ }
+ }
+
items.push_back(std::string("Subfolder Separator"));
if (!is_system_folder && !isRootFolder())
{
@@ -842,6 +874,17 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
if(is_agent_inventory)
{
items.push_back(std::string("Cut"));
+ if (!is_in_trash)
+ {
+ if (get_is_favorite(obj))
+ {
+ items.push_back(std::string("Remove from Favorites"));
+ }
+ else
+ {
+ items.push_back(std::string("Add to Favorites"));
+ }
+ }
if (!is_link || !is_cof || !get_is_item_worn(selected_id))
{
items.push_back(std::string("Delete"));
@@ -980,6 +1023,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
}
disabled_items.push_back(std::string("New Folder"));
+ disabled_items.push_back(std::string("upload_options"));
disabled_items.push_back(std::string("upload_def"));
disabled_items.push_back(std::string("create_new"));
}
@@ -1001,9 +1045,8 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
{
if (is_folder)
{
- LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
- if (cat
- && !LLFolderType::lookupIsProtectedType(cat->getPreferredType())
+ if (selected_category
+ && !LLFolderType::lookupIsProtectedType(selected_category->getPreferredType())
&& gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID()))
{
can_list = true;
@@ -1030,6 +1073,15 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
disabled_items.push_back(std::string("Marketplace Move"));
}
}
+
+ if (get_is_favorite(obj))
+ {
+ items.push_back(std::string("Remove from Favorites"));
+ }
+ else if (is_agent_inventory)
+ {
+ items.push_back(std::string("Add to Favorites"));
+ }
}
hide_context_entries(*menu, items, disabled_items);
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp
index 9e936eee5b..63d3117e77 100644
--- a/indra/newview/llinventoryitemslist.cpp
+++ b/indra/newview/llinventoryitemslist.cpp
@@ -115,7 +115,7 @@ void LLInventoryItemsList::doIdle()
{
if (mRefreshState == REFRESH_COMPLETE) return;
- if (isInVisibleChain() || mForceRefresh )
+ if (isInVisibleChain() || mForceRefresh || !getFilterSubString().empty())
{
refresh();
diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp
new file mode 100644
index 0000000000..88b07c0b0b
--- /dev/null
+++ b/indra/newview/llinventorylistener.cpp
@@ -0,0 +1,394 @@
+/**
+ * @file llinventorylistener.cpp
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventorylistener.h"
+
+#include "llappearancemgr.h"
+#include "llinventoryfunctions.h"
+#include "lltransutil.h"
+#include "llwearableitemslist.h"
+#include "resultset.h"
+#include "stringize.h"
+#include <algorithm> // std::min()
+
+constexpr S32 MAX_ITEM_LIMIT = 100;
+
+LLInventoryListener::LLInventoryListener()
+ : LLEventAPI("LLInventory",
+ "API for interactions with viewer Inventory items")
+{
+ add("getItemsInfo",
+ "Return information about items or folders defined in [\"item_ids\"]:\n"
+ "reply will contain [\"items\"] and [\"categories\"] result set keys",
+ &LLInventoryListener::getItemsInfo,
+ llsd::map("item_ids", LLSD(), "reply", LLSD()));
+
+ add("getFolderTypeNames",
+ "Return the table of folder type names, contained in [\"names\"]\n",
+ &LLInventoryListener::getFolderTypeNames,
+ llsd::map("reply", LLSD()));
+
+ add("getAssetTypeNames",
+ "Return the table of asset type names, contained in [\"names\"]\n",
+ &LLInventoryListener::getAssetTypeNames,
+ llsd::map("reply", LLSD()));
+
+ add("getBasicFolderID",
+ "Return the UUID of the folder by specified folder type name, for example:\n"
+ "\"Textures\", \"My outfits\", \"Sounds\" and other basic folders which have associated type",
+ &LLInventoryListener::getBasicFolderID,
+ llsd::map("ft_name", LLSD(), "reply", LLSD()));
+
+ add("getDirectDescendants",
+ "Return result set keys [\"categories\"] and [\"items\"] for the direct\n"
+ "descendants of the [\"folder_id\"]",
+ &LLInventoryListener::getDirectDescendants,
+ llsd::map("folder_id", LLSD(), "reply", LLSD()));
+
+ add("collectDescendantsIf",
+ "Return result set keys [\"categories\"] and [\"items\"] for the descendants\n"
+ "of the [\"folder_id\"], if it passes specified filters:\n"
+ "[\"name\"] is a substring of object's name,\n"
+ "[\"desc\"] is a substring of object's description,\n"
+ "asset [\"type\"] corresponds to the string name of the object's asset type\n"
+ "[\"limit\"] sets item count limit in result set (default unlimited)\n"
+ "[\"filter_links\"]: EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)",
+ &LLInventoryListener::collectDescendantsIf,
+ llsd::map("folder_id", LLSD(), "reply", LLSD()));
+
+/*==========================================================================*|
+ add("getSingle",
+ "Return LLSD [\"single\"] for a single folder or item from the specified\n"
+ "[\"result\"] key at the specified 0-relative [\"index\"].",
+ &LLInventoryListener::getSingle,
+ llsd::map("result", LLSD::Integer(), "index", LLSD::Integer(),
+ "reply", LLSD::String()));
+|*==========================================================================*/
+
+ add("getSlice",
+ stringize(
+ "Return an LLSD array [\"slice\"] from the specified [\"result\"] key\n"
+ "starting at 0-relative [\"index\"] with (up to) [\"count\"] entries.\n"
+ "count is limited to ", MAX_ITEM_LIMIT, " (default and max)."),
+ &LLInventoryListener::getSlice,
+ llsd::map("result", LLSD::Integer(), "index", LLSD::Integer(),
+ "reply", LLSD::String()));
+
+ add("closeResult",
+ "Release resources associated with specified [\"result\"] key,\n"
+ "or keys if [\"result\"] is an array.",
+ &LLInventoryListener::closeResult,
+ llsd::map("result", LLSD()));
+}
+
+// This struct captures (possibly large) category results from
+// getDirectDescendants() and collectDescendantsIf().
+struct CatResultSet: public LL::ResultSet
+{
+ CatResultSet(): LL::ResultSet("categories") {}
+ LLInventoryModel::cat_array_t mCategories;
+
+ int getLength() const override { return narrow(mCategories.size()); }
+ LLSD getSingle(int index) const override
+ {
+ auto cat = mCategories[index];
+ return llsd::map("id", cat->getUUID(),
+ "name", cat->getName(),
+ "parent_id", cat->getParentUUID(),
+ "type", LLFolderType::lookup(cat->getPreferredType()));
+ }
+};
+
+// This struct captures (possibly large) item results from
+// getDirectDescendants() and collectDescendantsIf().
+struct ItemResultSet: public LL::ResultSet
+{
+ ItemResultSet(): LL::ResultSet("items") {}
+ LLInventoryModel::item_array_t mItems;
+
+ int getLength() const override { return narrow(mItems.size()); }
+ LLSD getSingle(int index) const override
+ {
+ auto item = mItems[index];
+ return llsd::map("id", item->getUUID(),
+ "name", item->getName(),
+ "parent_id", item->getParentUUID(),
+ "desc", item->getDescription(),
+ "inv_type", LLInventoryType::lookup(item->getInventoryType()),
+ "asset_type", LLAssetType::lookup(item->getType()),
+ "creation_date", LLSD::Integer(item->getCreationDate()),
+ "asset_id", item->getAssetUUID(),
+ "is_link", item->getIsLinkType(),
+ "linked_id", item->getLinkedUUID());
+ }
+};
+
+void LLInventoryListener::getItemsInfo(LLSD const &data)
+{
+ Response response(LLSD(), data);
+
+ auto catresult = new CatResultSet;
+ auto itemresult = new ItemResultSet;
+
+ uuid_vec_t ids = LLSDParam<uuid_vec_t>(data["item_ids"]);
+ for (auto &it : ids)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(it);
+ if (item)
+ {
+ itemresult->mItems.push_back(item);
+ }
+ else
+ {
+ LLViewerInventoryCategory *cat = gInventory.getCategory(it);
+ if (cat)
+ {
+ catresult->mCategories.push_back(cat);
+ }
+ }
+ }
+ // Each of categories and items is a { result set key, total length } pair.
+ response["categories"] = catresult->getKeyLength();
+ response["items"] = itemresult->getKeyLength();
+}
+
+void LLInventoryListener::getFolderTypeNames(LLSD const &data)
+{
+ Response response(llsd::map("names", LLFolderType::getTypeNames()), data);
+}
+
+void LLInventoryListener::getAssetTypeNames(LLSD const &data)
+{
+ Response response(llsd::map("names", LLAssetType::getTypeNames()), data);
+}
+
+void LLInventoryListener::getBasicFolderID(LLSD const &data)
+{
+ Response response(llsd::map("id", gInventory.findCategoryUUIDForType(LLFolderType::lookup(data["ft_name"].asString()))), data);
+}
+
+
+void LLInventoryListener::getDirectDescendants(LLSD const &data)
+{
+ Response response(LLSD(), data);
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(data["folder_id"], cats, items);
+
+ auto catresult = new CatResultSet;
+ auto itemresult = new ItemResultSet;
+
+ catresult->mCategories = *cats;
+ itemresult->mItems = *items;
+
+ response["categories"] = catresult->getKeyLength();
+ response["items"] = itemresult->getKeyLength();
+}
+
+struct LLFilteredCollector : public LLInventoryCollectFunctor
+{
+ enum EFilterLink
+ {
+ INCLUDE_LINKS, // show links too
+ EXCLUDE_LINKS, // don't show links
+ ONLY_LINKS // only show links
+ };
+
+ LLFilteredCollector(LLSD const &data);
+ virtual ~LLFilteredCollector() {}
+ virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item) override;
+ virtual bool exceedsLimit() override
+ {
+ // mItemLimit == 0 means unlimited
+ return (mItemLimit && mItemLimit <= mItemCount);
+ }
+
+ protected:
+ bool checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item);
+ bool checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item);
+ bool checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item);
+
+ LLAssetType::EType mType;
+ std::string mName;
+ std::string mDesc;
+ EFilterLink mLinkFilter;
+
+ S32 mItemLimit;
+ S32 mItemCount;
+};
+
+void LLInventoryListener::collectDescendantsIf(LLSD const &data)
+{
+ Response response(LLSD(), data);
+ LLUUID folder_id(data["folder_id"].asUUID());
+ LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id);
+ if (!cat)
+ {
+ return response.error(stringize("Folder ", std::quoted(data["folder_id"].asString()), " was not found"));
+ }
+ auto catresult = new CatResultSet;
+ auto itemresult = new ItemResultSet;
+
+ LLFilteredCollector collector = LLFilteredCollector(data);
+
+ // Populate results directly into the catresult and itemresult arrays.
+ // TODO: sprinkle count-based coroutine yields into the real
+ // collectDescendentsIf() method so it doesn't steal too many cycles.
+ gInventory.collectDescendentsIf(
+ folder_id,
+ catresult->mCategories,
+ itemresult->mItems,
+ LLInventoryModel::EXCLUDE_TRASH,
+ collector);
+
+ response["categories"] = catresult->getKeyLength();
+ response["items"] = itemresult->getKeyLength();
+}
+
+/*==========================================================================*|
+void LLInventoryListener::getSingle(LLSD const& data)
+{
+ auto result = LL::ResultSet::getInstance(data["result"]);
+ sendReply(llsd::map("single", result->getSingle(data["index"])), data);
+}
+|*==========================================================================*/
+
+void LLInventoryListener::getSlice(LLSD const& data)
+{
+ auto result = LL::ResultSet::getInstance(data["result"]);
+ int count = data.has("count")? data["count"].asInteger() : MAX_ITEM_LIMIT;
+ LL_DEBUGS("Lua") << *result << ".getSlice(" << data["index"].asInteger()
+ << ", " << count << ')' << LL_ENDL;
+ auto pair{ result->getSliceStart(data["index"], std::min(count, MAX_ITEM_LIMIT)) };
+ sendReply(llsd::map("slice", pair.first, "start", pair.second), data);
+}
+
+void LLInventoryListener::closeResult(LLSD const& data)
+{
+ LLSD results = data["result"];
+ if (results.isInteger())
+ {
+ results = llsd::array(results);
+ }
+ for (const auto& result : llsd::inArray(results))
+ {
+ auto ptr = LL::ResultSet::getInstance(result);
+ if (ptr)
+ {
+ delete ptr.get();
+ }
+ }
+}
+
+LLFilteredCollector::LLFilteredCollector(LLSD const &data) :
+ mType(LLAssetType::EType::AT_UNKNOWN),
+ mLinkFilter(INCLUDE_LINKS),
+ mItemLimit(0),
+ mItemCount(0)
+{
+
+ mName = data["name"].asString();
+ mDesc = data["desc"].asString();
+
+ if (data.has("type"))
+ {
+ mType = LLAssetType::lookup(data["type"]);
+ }
+ if (data.has("filter_links"))
+ {
+ if (data["filter_links"] == "EXCLUDE_LINKS")
+ {
+ mLinkFilter = EXCLUDE_LINKS;
+ }
+ else if (data["filter_links"] == "ONLY_LINKS")
+ {
+ mLinkFilter = ONLY_LINKS;
+ }
+ }
+ if (data["limit"].isInteger())
+ {
+ mItemLimit = std::max(data["limit"].asInteger(), 1);
+ }
+}
+
+bool LLFilteredCollector::operator()(LLInventoryCategory *cat, LLInventoryItem *item)
+{
+ bool passed = checkagainstType(cat, item);
+ passed = passed && checkagainstNameDesc(cat, item);
+ passed = passed && checkagainstLinks(cat, item);
+
+ if (passed)
+ {
+ ++mItemCount;
+ }
+ return passed;
+}
+
+bool LLFilteredCollector::checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item)
+{
+ std::string name, desc;
+ bool passed(true);
+ if (cat)
+ {
+ if (!mDesc.empty()) return false;
+ name = cat->getName();
+ }
+ if (item)
+ {
+ name = item->getName();
+ passed = (mDesc.empty() || (item->getDescription().find(mDesc) != std::string::npos));
+ }
+
+ return passed && (mName.empty() || name.find(mName) != std::string::npos);
+}
+
+bool LLFilteredCollector::checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item)
+{
+ if (mType == LLAssetType::AT_UNKNOWN)
+ {
+ return true;
+ }
+ if (cat && (mType == LLAssetType::AT_CATEGORY))
+ {
+ return true;
+ }
+ if (item && item->getType() == mType)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool LLFilteredCollector::checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item)
+{
+ bool is_link = cat ? cat->getIsLinkType() : item->getIsLinkType();
+ if (is_link && (mLinkFilter == EXCLUDE_LINKS))
+ return false;
+ if (!is_link && (mLinkFilter == ONLY_LINKS))
+ return false;
+ return true;
+}
diff --git a/indra/newview/llinventorylistener.h b/indra/newview/llinventorylistener.h
new file mode 100644
index 0000000000..a05385f2c8
--- /dev/null
+++ b/indra/newview/llinventorylistener.h
@@ -0,0 +1,53 @@
+/**
+ * @file llinventorylistener.h
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLINVENTORYLISTENER_H
+#define LL_LLINVENTORYLISTENER_H
+
+#include "lleventapi.h"
+#include "llinventoryfunctions.h"
+
+class LLInventoryListener : public LLEventAPI
+{
+public:
+ LLInventoryListener();
+
+private:
+ void getItemsInfo(LLSD const &data);
+ void getFolderTypeNames(LLSD const &data);
+ void getAssetTypeNames(LLSD const &data);
+ void getBasicFolderID(LLSD const &data);
+ void getDirectDescendants(LLSD const &data);
+ void collectDescendantsIf(LLSD const &data);
+/*==========================================================================*|
+ void getSingle(LLSD const& data);
+|*==========================================================================*/
+ void getSlice(LLSD const& data);
+ void closeResult(LLSD const& data);
+};
+
+#endif // LL_LLINVENTORYLISTENER_H
+
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 53ea02983a..ccb5a59bf8 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -78,7 +78,7 @@
// Increment this if the inventory contents change in a non-backwards-compatible way.
// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
-const S32 LLInventoryModel::sCurrentInvCacheVersion = 3;
+const S32 LLInventoryModel::sCurrentInvCacheVersion = 4;
bool LLInventoryModel::sFirstTimeInViewer2 = true;
S32 LLInventoryModel::sPendingSystemFolders = 0;
@@ -1282,6 +1282,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
{
for (auto& cat : *cat_array)
{
+ if (add.exceedsLimit())
+ {
+ break;
+ }
if(add(cat,NULL))
{
cats.push_back(cat);
@@ -1297,6 +1301,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
{
for (auto& item : *item_array)
{
+ if (add.exceedsLimit())
+ {
+ break;
+ }
if(add(NULL, item))
{
items.push_back(item);
@@ -2765,8 +2773,9 @@ bool LLInventoryModel::loadSkeleton(
cached_ids.insert(tcat->getUUID());
// At the moment download does not provide a thumbnail
- // uuid, use the one from cache
+ // uuid or favorite, use values from cache
tcat->setThumbnailUUID(cat->getThumbnailUUID());
+ tcat->setFavorite(cat->getIsFavorite());
}
}
@@ -4824,6 +4833,17 @@ std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const
return result;
}
+/*
+const LLInventoryObject* LLInventoryModel::findByFullPath(const std::string& path)
+{
+ vector<std::string> path_elts;
+ boost::algorithm::split(path_elts, path, boost::is_any_of("/"));
+ for(path_elts, auto e)
+ {
+ }
+}
+*/
+
///----------------------------------------------------------------------------
/// Local function definitions
///----------------------------------------------------------------------------
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index ac791e224e..ac22be9d5a 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -749,6 +749,13 @@ void LLInventoryCategoriesObserver::changed(U32 mask)
cat_changed = true;
}
+ bool is_favorite = category->getIsFavorite();
+ if (cat_data.mIsFavorite != is_favorite)
+ {
+ cat_data.mIsFavorite = is_favorite;
+ cat_changed = true;
+ }
+
// If anything has changed above, fire the callback.
if (cat_changed)
cat_data.mCallback();
@@ -766,6 +773,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN;
S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN;
bool can_be_added = true;
+ bool favorite = false;
LLUUID thumbnail_id;
LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
@@ -779,6 +787,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
// to a category have been made.
version = category->getVersion();
thumbnail_id = category->getThumbnailUUID();
+ favorite = category->getIsFavorite();
LLInventoryModel::cat_array_t* cats;
LLInventoryModel::item_array_t* items;
@@ -804,11 +813,11 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t
if(init_name_hash)
{
digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id);
- mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash)));
+ mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents,item_name_hash)));
}
else
{
- mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents)));
+ mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents)));
}
}
@@ -821,25 +830,37 @@ void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
}
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
- const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents)
+ const LLUUID& cat_id,
+ const LLUUID& thumbnail_id,
+ bool is_favorite,
+ callback_t cb,
+ S32 version,
+ S32 num_descendents)
: mCatID(cat_id)
, mCallback(cb)
, mVersion(version)
, mDescendentsCount(num_descendents)
, mThumbnailId(thumbnail_id)
+ , mIsFavorite(is_favorite)
, mIsNameHashInitialized(false)
{
}
LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(
- const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash)
+ const LLUUID& cat_id,
+ const LLUUID& thumbnail_id,
+ bool is_favorite,
+ callback_t cb, S32 version,
+ S32 num_descendents,
+ const digest_t& name_hash)
: mCatID(cat_id)
, mCallback(cb)
, mVersion(version)
, mDescendentsCount(num_descendents)
, mThumbnailId(thumbnail_id)
+ , mIsFavorite(is_favorite)
, mIsNameHashInitialized(true)
, mItemNameHash(name_hash)
{
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index 950b02d3cf..12d6c44521 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -60,6 +60,7 @@ public:
CREATE = 512, // With ADD, item has just been created.
// unfortunately a particular message is still associated with some unique semantics.
UPDATE_CREATE = 1024, // With ADD, item added via UpdateCreateInventoryItem
+ UPDATE_FAVORITE = 2048, // With ADD, item added via UpdateCreateInventoryItem
ALL = 0xffffffff
};
LLInventoryObserver();
@@ -276,12 +277,26 @@ protected:
typedef LLUUID digest_t; // To clarify the actual usage of this "UUID"
struct LLCategoryData
{
- LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents);
- LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash);
+ LLCategoryData(
+ const LLUUID& cat_id,
+ const LLUUID& thumbnail_id,
+ bool is_favorite,
+ callback_t cb,
+ S32 version,
+ S32 num_descendents);
+ LLCategoryData(
+ const LLUUID& cat_id,
+ const LLUUID& thumbnail_id,
+ bool is_favorite,
+ callback_t cb,
+ S32 version,
+ S32 num_descendents,
+ const digest_t& name_hash);
callback_t mCallback;
S32 mVersion;
S32 mDescendentsCount;
digest_t mItemNameHash;
+ bool mIsFavorite;
bool mIsNameHashInitialized;
LLUUID mCatID;
LLUUID mThumbnailId;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index bf12e6a7e0..cba69d5b4f 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -55,11 +55,13 @@
#include "llviewerfoldertype.h"
#include "llvoavatarself.h"
+class LLInventoryFavoritesItemsPanel;
class LLInventoryRecentItemsPanel;
class LLAssetFilteredInventoryPanel;
static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel");
static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel");
+static LLDefaultChildRegistry::Register<LLInventoryFavoritesItemsPanel> t_favorites_inventory_panel("favorites_inventory_panel");
static LLDefaultChildRegistry::Register<LLAssetFilteredInventoryPanel> t_asset_filtered_inv_panel("asset_filtered_inv_panel");
const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
@@ -177,16 +179,15 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
}
// context menu callbacks
- mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2));
- mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
- mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
- mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2));
- mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2));
- mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this));
- mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this));
- mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2));
- mCommitCallbackRegistrar.add("Inventory.SetFavoriteFolder", boost::bind(&LLInventoryPanel::setFavoriteFolder, this));
- mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()));
+ mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLInventoryPanel::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.EmptyTrash", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.DoCreate", { boost::bind(&LLInventoryPanel::doCreate, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.AttachObject", { boost::bind(&LLInventoryPanel::attachObject, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.BeginIMSession", { boost::bind(&LLInventoryPanel::beginIMSession, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.Share", { boost::bind(&LLAvatarActions::shareWithAvatars, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", { boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", { boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()), LLUICtrl::cb_info::UNTRUSTED_THROTTLE });
}
LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
@@ -623,6 +624,19 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
}
}
+ if (mask & LLInventoryObserver::UPDATE_FAVORITE)
+ {
+ if (view_item)
+ {
+ view_item->refresh();
+ LLFolderViewFolder* parent = view_item->getParentFolder();
+ if (parent)
+ {
+ parent->updateHasFavorites(get_is_favorite(model_item));
+ }
+ }
+ }
+
// We don't typically care which of these masks the item is actually flagged with, since the masks
// may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into
// Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks
@@ -651,6 +665,16 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
setSelection(item_id, false);
}
updateFolderLabel(model_item->getParentUUID());
+
+ if (get_is_favorite(model_item))
+ {
+ LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID());
+ if (new_parent)
+ {
+ new_parent->updateHasFavorites(true);
+ }
+ }
+
}
//////////////////////////////
@@ -701,6 +725,12 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
{
old_parent_vmi->dirtyDescendantsFilter();
}
+
+ if (view_item->isFavorite())
+ {
+ old_parent->updateHasFavorites(false); // favorite was removed
+ new_parent->updateHasFavorites(true); // favorite was added
+ }
}
}
}
@@ -726,6 +756,10 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
updateFolderLabel(viewmodel_folder->getUUID());
}
}
+ if (view_item->isFavorite())
+ {
+ parent->updateHasFavorites(false); // favorite was removed
+ }
}
}
}
@@ -843,7 +877,23 @@ void LLInventoryPanel::idle(void* user_data)
bool in_visible_chain = panel->isInVisibleChain();
- if (!panel->mBuildViewsQueue.empty())
+ if (!panel->mBuildRootQueue.empty())
+ {
+ const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms
+ F64 curent_time = LLTimer::getTotalSeconds();
+ panel->mBuildViewsEndTime = curent_time + max_time;
+
+ while (curent_time < panel->mBuildViewsEndTime
+ && !panel->mBuildRootQueue.empty())
+ {
+ LLUUID item_id = panel->mBuildRootQueue.back();
+ panel->mBuildRootQueue.pop_back();
+ panel->findAndInitRootContent(item_id);
+
+ curent_time = LLTimer::getTotalSeconds();
+ }
+ }
+ else if (!panel->mBuildViewsQueue.empty())
{
const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms
F64 curent_time = LLTimer::getTotalSeconds();
@@ -925,20 +975,9 @@ void LLInventoryPanel::initializeViews(F64 max_time)
mBuildViewsEndTime = curent_time + max_time;
// init everything
- LLUUID root_id = getRootFolderID();
- if (root_id.notNull())
- {
- buildNewViews(getRootFolderID());
- }
- else
- {
- // Default case: always add "My Inventory" root first, "Library" root second
- // If we run out of time, this still should create root folders
- buildNewViews(gInventory.getRootFolderID()); // My Inventory
- buildNewViews(gInventory.getLibraryRootFolderID()); // Library
- }
+ initRootContent();
- if (mBuildViewsQueue.empty())
+ if (mBuildViewsQueue.empty() && mBuildRootQueue.empty())
{
mViewsInitialized = VIEWS_INITIALIZED;
}
@@ -969,6 +1008,21 @@ void LLInventoryPanel::initializeViews(F64 max_time)
}
}
+void LLInventoryPanel::initRootContent()
+{
+ LLUUID root_id = getRootFolderID();
+ if (root_id.notNull())
+ {
+ buildNewViews(getRootFolderID());
+ }
+ else
+ {
+ // Default case: always add "My Inventory" root first, "Library" root second
+ // If we run out of time, this still should create root folders
+ buildNewViews(gInventory.getRootFolderID()); // My Inventory
+ buildNewViews(gInventory.getLibraryRootFolderID()); // Library
+ }
+}
LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop)
{
@@ -1738,26 +1792,8 @@ bool LLInventoryPanel::beginIMSession()
void LLInventoryPanel::fileUploadLocation(const LLSD& userdata)
{
const std::string param = userdata.asString();
- if (param == "model")
- {
- gSavedPerAccountSettings.setString("ModelUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
- }
- else if (param == "texture")
- {
- gSavedPerAccountSettings.setString("TextureUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
- }
- else if (param == "sound")
- {
- gSavedPerAccountSettings.setString("SoundUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
- }
- else if (param == "animation")
- {
- gSavedPerAccountSettings.setString("AnimationUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
- }
- else if (param == "pbr_material")
- {
- gSavedPerAccountSettings.setString("PBRUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString());
- }
+ const LLUUID dest = LLFolderBridge::sSelf.get()->getUUID();
+ LLInventoryAction::fileUploadLocation(dest, param);
}
void LLInventoryPanel::setFavoriteFolder()
@@ -2210,6 +2246,249 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
}
+/************************************************************************/
+/* Favorites Inventory Panel related class */
+/************************************************************************/
+static const LLFavoritesInventoryBridgeBuilder FAVORITES_BUILDER;
+class LLInventoryFavoritesItemsPanel : public LLInventoryPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
+ {};
+
+ void initFromParams(const Params& p)
+ {
+ LLInventoryPanel::initFromParams(p);
+ // turn off trash
+ getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() | (1ULL << LLFolderType::FT_TRASH));
+ getFilter().setFilterNoTrashFolder();
+ // turn off marketplace for favorites
+ getFilter().setFilterNoMarketplaceFolder();
+ }
+
+ void removeItemID(const LLUUID& id) override;
+
+protected:
+ LLInventoryFavoritesItemsPanel(const Params&);
+ friend class LLUICtrlFactory;
+
+ void findAndInitRootContent(const LLUUID& folder_id) override;
+ void initRootContent() override;
+
+ bool removeFavorite(const LLUUID& id, const LLInventoryObject* model_item);
+ void itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item) override;
+
+ std::set<LLUUID> mRootContentIDs;
+};
+
+LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& params)
+ : LLInventoryPanel(params)
+{
+ // replace bridge builder to have necessary View bridges.
+ mInvFVBridgeBuilder = &FAVORITES_BUILDER;
+}
+
+void LLInventoryFavoritesItemsPanel::removeItemID(const LLUUID& id)
+{
+ std::set<LLUUID>::iterator found = mRootContentIDs.find(id);
+ if (found != mRootContentIDs.end())
+ {
+ mRootContentIDs.erase(found);
+ // check content for favorites
+ mBuildRootQueue.emplace_back(id);
+ }
+
+ LLInventoryPanel::removeItemID(id);
+}
+
+void LLInventoryFavoritesItemsPanel::findAndInitRootContent(const LLUUID& id)
+{
+ F64 curent_time = LLTimer::getTotalSeconds();
+ if (mBuildViewsEndTime < curent_time)
+ {
+ mBuildRootQueue.emplace_back(id);
+ return;
+ }
+ LLViewerInventoryCategory::cat_array_t* categories;
+ LLViewerInventoryItem::item_array_t* items;
+ mInventory->lockDirectDescendentArrays(id, categories, items);
+
+ if (categories)
+ {
+ size_t count = categories->size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ LLViewerInventoryCategory* cat = categories->at(i);
+ if (cat->getPreferredType() == LLFolderType::FT_TRASH)
+ {
+ continue;
+ }
+ else if (cat->getIsFavorite())
+ {
+ LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID());
+ if (!folder_view_item)
+ {
+ const LLUUID& parent_id = cat->getParentUUID();
+ mRootContentIDs.emplace(cat->getUUID());
+
+ buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT);
+ }
+ }
+ else
+ {
+ findAndInitRootContent(cat->getUUID());
+ }
+ }
+ }
+
+ if (items)
+ {
+ size_t count = items->size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ LLViewerInventoryItem* item = items->at(i);
+ const LLUUID item_id = item->getUUID();
+ if (item->getIsFavorite() && typedViewsFilter(item_id, item))
+ {
+ LLFolderViewItem* folder_view_item = getItemByID(id);
+ if (!folder_view_item)
+ {
+ const LLUUID& parent_id = item->getParentUUID();
+ mRootContentIDs.emplace(item_id);
+
+ buildViewsTree(item_id, parent_id, item, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT);
+ }
+ }
+ }
+ }
+
+ mInventory->unlockDirectDescendentArrays(id);
+}
+
+void LLInventoryFavoritesItemsPanel::initRootContent()
+{
+ findAndInitRootContent(gInventory.getRootFolderID()); // My Inventory
+}
+
+bool LLInventoryFavoritesItemsPanel::removeFavorite(const LLUUID& id, const LLInventoryObject* model_item)
+{
+ std::set<LLUUID>::iterator found = mRootContentIDs.find(id);
+ if (found == mRootContentIDs.end())
+ {
+ return false;
+ }
+
+ mRootContentIDs.erase(found);
+
+ // This item is in root's content, remove item's UI.
+ LLFolderViewItem* view_item = getItemByID(id);
+ if (view_item)
+ {
+ LLFolderViewFolder* parent = view_item->getParentFolder();
+ LLFolderViewModelItemInventory* viewmodel_item = static_cast<LLFolderViewModelItemInventory*>(view_item->getViewModelItem());
+ if (viewmodel_item)
+ {
+ removeItemID(viewmodel_item->getUUID());
+ }
+ view_item->destroyView();
+ if (parent)
+ {
+ parent->getViewModelItem()->dirtyDescendantsFilter();
+ LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(parent->getViewModelItem());
+ if (viewmodel_folder)
+ {
+ updateFolderLabel(viewmodel_folder->getUUID());
+ }
+ if (view_item->isFavorite())
+ {
+ parent->updateHasFavorites(false); // favorite was removed
+ }
+ }
+ }
+
+ return true;
+}
+
+void LLInventoryFavoritesItemsPanel::itemChanged(const LLUUID& id, U32 mask, const LLInventoryObject* model_item)
+{
+ if (!model_item && !getItemByID(id))
+ {
+ // remove operation, but item is not in panel already
+ return;
+ }
+
+ bool handled = false;
+
+ if (mask & (LLInventoryObserver::UPDATE_FAVORITE |
+ LLInventoryObserver::STRUCTURE |
+ LLInventoryObserver::ADD |
+ LLInventoryObserver::REMOVE))
+ {
+ // specifically exlude links and not get_is_favorite(model_item)
+ if (model_item && model_item->getIsFavorite())
+ {
+ LLFolderViewItem* view_item = getItemByID(id);
+ if (!view_item)
+ {
+ const LLViewerInventoryCategory* cat = dynamic_cast<const LLViewerInventoryCategory*>(model_item);
+ if (cat)
+ {
+ // New favorite folder
+ if (cat->getPreferredType() != LLFolderType::FT_TRASH)
+ {
+ // If any descendants were in the list, remove them
+ LLFavoritesCollector is_favorite;
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectDescendentsIf(id, cat_array, item_array, false, is_favorite);
+ for (LLInventoryModel::cat_array_t::const_iterator it = cat_array.begin(); it != cat_array.end(); ++it)
+ {
+ removeFavorite((*it)->getUUID(), *it);
+ }
+ for (LLInventoryModel::item_array_t::const_iterator it = item_array.begin(); it != item_array.end(); ++it)
+ {
+ removeFavorite((*it)->getUUID(), *it);
+ }
+
+ LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID());
+ if (!folder_view_item)
+ {
+ const LLUUID& parent_id = cat->getParentUUID();
+ mRootContentIDs.emplace(cat->getUUID());
+
+ buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_ONE_FOLDER);
+ }
+ }
+ }
+ else
+ {
+ // New favorite item
+ if (model_item->getIsFavorite() && typedViewsFilter(id, model_item))
+ {
+ const LLUUID& parent_id = model_item->getParentUUID();
+ mRootContentIDs.emplace(id);
+
+ buildViewsTree(id, parent_id, model_item, NULL, mFolderRoot.get(), BUILD_ONE_FOLDER);
+ }
+ }
+ handled = true;
+ }
+ }
+ else
+ {
+ handled = removeFavorite(id, model_item);
+ }
+ }
+
+ if (!handled)
+ {
+ LLInventoryPanel::itemChanged(id, mask, model_item);
+ }
+}
+/************************************************************************/
+/* LLInventorySingleFolderPanel */
+/************************************************************************/
+
static LLDefaultChildRegistry::Register<LLInventorySingleFolderPanel> t_single_folder_inventory_panel("single_folder_inventory_panel");
LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)
@@ -2220,9 +2499,9 @@ LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)
getFilter().setEmptyLookupMessage("InventorySingleFolderNoMatches");
getFilter().setDefaultEmptyLookupMessage("InventorySingleFolderEmpty");
- mCommitCallbackRegistrar.replace("Inventory.DoToSelected", boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2));
- mCommitCallbackRegistrar.replace("Inventory.DoCreate", boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2));
- mCommitCallbackRegistrar.replace("Inventory.Share", boost::bind(&LLInventorySingleFolderPanel::doShare, this));
+ mCommitCallbackRegistrar.replace("Inventory.DoToSelected", { boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.replace("Inventory.DoCreate", { boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.replace("Inventory.Share", { boost::bind(&LLInventorySingleFolderPanel::doShare, this), cb_info::UNTRUSTED_BLOCK });
}
LLInventorySingleFolderPanel::~LLInventorySingleFolderPanel()
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index ab17196e5f..6f7a2193ac 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -252,7 +252,7 @@ public:
bool reset_filter = false);
static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id);
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
- void removeItemID(const LLUUID& id);
+ virtual void removeItemID(const LLUUID& id);
LLFolderViewItem* getItemByID(const LLUUID& id);
LLFolderViewFolder* getFolderByID(const LLUUID& id);
void setSelectionByID(const LLUUID& obj_id, bool take_keyboard_focus);
@@ -335,6 +335,8 @@ public:
protected:
// Builds the UI. Call this once the inventory is usable.
void initializeViews(F64 max_time);
+ virtual void initRootContent();
+ virtual void findAndInitRootContent(const LLUUID& root_id) {};
// Specific inventory colors
static bool sColorSetInitialized;
@@ -372,7 +374,7 @@ protected:
virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge);
boost::function<void(const std::deque<LLFolderViewItem*>& items, bool user_action)> mSelectionCallback;
-private:
+protected:
// buildViewsTree does not include some checks and is meant
// for recursive use, use buildNewViews() for first call
LLFolderViewItem* buildViewsTree(const LLUUID& id,
@@ -395,6 +397,7 @@ private:
EViewsInitializationState mViewsInitialized; // Whether views have been generated
F64 mBuildViewsEndTime; // Stop building views past this timestamp
std::deque<LLUUID> mBuildViewsQueue;
+ std::deque<LLUUID> mBuildRootQueue;
};
diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp
index 666ab4f5d0..b9456349cd 100644
--- a/indra/newview/llkeyconflict.cpp
+++ b/indra/newview/llkeyconflict.cpp
@@ -99,29 +99,34 @@ LLKeyConflictHandler::~LLKeyConflictHandler()
// Note: does not reset bindings if temporary file was used
}
-bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask)
+bool LLKeyConflictHandler::canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask) const
{
- return mControlsMap[control_name].canHandle(mouse_ind, key, mask);
+ control_map_t::const_iterator iter = mControlsMap.find(control_name);
+ if (iter != mControlsMap.end())
+ {
+ return iter->second.canHandle(mouse_ind, key, mask);
+ }
+ return false;
}
-bool LLKeyConflictHandler::canHandleKey(const std::string &control_name, KEY key, MASK mask)
+bool LLKeyConflictHandler::canHandleKey(const std::string &control_name, KEY key, MASK mask) const
{
return canHandleControl(control_name, CLICK_NONE, key, mask);
}
-bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask)
+bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask) const
{
return canHandleControl(control_name, mouse_ind, KEY_NONE, mask);
}
-bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask)
+bool LLKeyConflictHandler::canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask) const
{
return canHandleControl(control_name, (EMouseClickType)mouse_ind, KEY_NONE, mask);
}
-bool LLKeyConflictHandler::canAssignControl(const std::string &control_name)
+bool LLKeyConflictHandler::canAssignControl(const std::string &control_name) const
{
- control_map_t::iterator iter = mControlsMap.find(control_name);
+ control_map_t::const_iterator iter = mControlsMap.find(control_name);
if (iter != mControlsMap.end())
{
return iter->second.mAssignable;
@@ -284,7 +289,7 @@ void LLKeyConflictHandler::loadFromSettings(const LLViewerInput::KeyMode& keymod
LLKeyboard::keyFromString(it->key, &key);
}
LLKeyboard::maskFromString(it->mask, &mask);
- // Note: it->command is also the name of UI element, howhever xml we are loading from
+ // Note: it->command is also the name of UI element, however xml we are loading from
// might not know all the commands, so UI will have to know what to fill by its own
// Assumes U32_MAX conflict mask, and is assignable by default,
// but assignability might have been overriden by generatePlaceholders.
diff --git a/indra/newview/llkeyconflict.h b/indra/newview/llkeyconflict.h
index 6c01ddb7a7..21990688a2 100644
--- a/indra/newview/llkeyconflict.h
+++ b/indra/newview/llkeyconflict.h
@@ -44,7 +44,7 @@ public:
LLKeyData getKeyData(U32 index) { return mKeyBind.getKeyData(index); }
void setPrimaryKeyData(const LLKeyData& data) { mKeyBind.replaceKeyData(data, 0); }
void setKeyData(const LLKeyData& data, U32 index) { mKeyBind.replaceKeyData(data, index); }
- bool canHandle(EMouseClickType mouse, KEY key, MASK mask) { return mKeyBind.canHandle(mouse, key, mask); }
+ bool canHandle(EMouseClickType mouse, KEY key, MASK mask) const { return mKeyBind.canHandle(mouse, key, mask); }
LLKeyBind mKeyBind;
bool mAssignable; // whether user can change key or key simply acts as placeholder
@@ -76,11 +76,11 @@ public:
LLKeyConflictHandler(ESourceMode mode);
~LLKeyConflictHandler();
- bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask);
- bool canHandleKey(const std::string &control_name, KEY key, MASK mask);
- bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask);
- bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask); //Just for convinience
- bool canAssignControl(const std::string &control_name);
+ bool canHandleControl(const std::string &control_name, EMouseClickType mouse_ind, KEY key, MASK mask) const;
+ bool canHandleKey(const std::string &control_name, KEY key, MASK mask) const;
+ bool canHandleMouse(const std::string &control_name, EMouseClickType mouse_ind, MASK mask) const;
+ bool canHandleMouse(const std::string &control_name, S32 mouse_ind, MASK mask) const; //Just for convenience
+ bool canAssignControl(const std::string &control_name) const;
static bool isReservedByMenu(const KEY &key, const MASK &mask);
static bool isReservedByMenu(const LLKeyData &data);
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 31c9eb8966..4d54eac2ba 100644
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -673,7 +673,7 @@ void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id)
LLFetchedGLTFMaterial* render_mat = dynamic_cast<LLFetchedGLTFMaterial*>(entry->getGLTFRenderMaterial());
if (render_mat)
{
- *render_mat = *fetched_mat;
+ *render_mat = *fetched_mat;
render_mat->applyOverride(*override_mat);
}
else
@@ -996,17 +996,12 @@ LLLocalBitmapTimer::~LLLocalBitmapTimer()
void LLLocalBitmapTimer::startTimer()
{
- mEventTimer.start();
+ start();
}
void LLLocalBitmapTimer::stopTimer()
{
- mEventTimer.stop();
-}
-
-bool LLLocalBitmapTimer::isRunning()
-{
- return mEventTimer.getStarted();
+ stop();
}
bool LLLocalBitmapTimer::tick()
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
index e169f96e70..4bad9ff9a5 100644
--- a/indra/newview/lllocalbitmaps.h
+++ b/indra/newview/lllocalbitmaps.h
@@ -120,8 +120,7 @@ class LLLocalBitmapTimer : public LLEventTimer
public:
void startTimer();
void stopTimer();
- bool isRunning();
- bool tick();
+ bool tick() override;
};
diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp
index fab18f2d26..3af1433a40 100644
--- a/indra/newview/lllocalgltfmaterials.cpp
+++ b/indra/newview/lllocalgltfmaterials.cpp
@@ -294,17 +294,12 @@ LLLocalGLTFMaterialTimer::~LLLocalGLTFMaterialTimer()
void LLLocalGLTFMaterialTimer::startTimer()
{
- mEventTimer.start();
+ start();
}
void LLLocalGLTFMaterialTimer::stopTimer()
{
- mEventTimer.stop();
-}
-
-bool LLLocalGLTFMaterialTimer::isRunning()
-{
- return mEventTimer.getStarted();
+ stop();
}
bool LLLocalGLTFMaterialTimer::tick()
diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h
index b806b54508..9c2d1bb287 100644
--- a/indra/newview/lllocalgltfmaterials.h
+++ b/indra/newview/lllocalgltfmaterials.h
@@ -89,8 +89,7 @@ public:
public:
void startTimer();
void stopTimer();
- bool isRunning();
- bool tick();
+ bool tick() override;
};
class LLLocalGLTFMaterialMgr : public LLSingleton<LLLocalGLTFMaterialMgr>
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 54dd5792a0..2c91fe06e9 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -377,7 +377,7 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
addChild(mParcelIcon[SEE_AVATARS_ICON]);
// Register callbacks and load the location field context menu (NB: the order matters).
- LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2));
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", { boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2) });
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2));
setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2));
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index bf49f33049..51f30dd86b 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -78,8 +78,8 @@ const static std::string MULTI_LINE_PREFIX(" ");
*
* Note: "You" was used as an avatar names in viewers of previous versions
*/
-const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]\\s+|\\[\\d{1,2}:\\d{2}\\]\\s+)?(.*)$");
-const static boost::regex TIMESTAMP("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]|\\[\\d{1,2}:\\d{2}\\]).*");
+const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\s[AaPp][Mm]\\]\\s+|\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}\\]\\s+|\\[\\d{1,2}:\\d{2}\\s[AaPp][Mm]\\]\\s+|\\[\\d{1,2}:\\d{2}\\]\\s+)?(.*)$");
+const static boost::regex TIMESTAMP("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{2}(\\s[AaPp][Mm])?\\]|\\[\\d{1,2}:\\d{2}(\\s[AaPp][Mm])?\\]).*");
/**
* Regular expression suitable to match names like
@@ -150,6 +150,10 @@ public:
void checkAndCutOffDate(std::string& time_str)
{
+ if (time_str.size() < 10) // not enough space for a date
+ {
+ return;
+ }
// Cuts off the "%Y/%m/%d" from string for todays timestamps.
// Assume that passed string has at least "%H:%M" time format.
date log_date(not_a_date_time);
@@ -166,20 +170,12 @@ public:
if ( days_alive == zero_days )
{
- // Yep, today's so strip "%Y/%m/%d" info
- ptime stripped_time(not_a_date_time);
-
- mTimeStream.str(LLStringUtil::null);
- mTimeStream << time_str;
- mTimeStream >> stripped_time;
- mTimeStream.clear();
-
- time_str.clear();
-
- mTimeStream.str(LLStringUtil::null);
- mTimeStream << stripped_time;
- mTimeStream >> time_str;
- mTimeStream.clear();
+ size_t pos = time_str.find_first_of(' ');
+ if (pos != std::string::npos)
+ {
+ time_str.erase(0, pos + 1);
+ LLStringUtil::trim(time_str);
+ }
}
LL_DEBUGS("LLChatLogParser")
@@ -308,16 +304,22 @@ std::string LLLogChat::timestamp2LogString(U32 timestamp, bool withdate)
std::string timeStr;
if (withdate)
{
- timeStr = "[" + LLTrans::getString ("TimeYear") + "]/["
- + LLTrans::getString ("TimeMonth") + "]/["
- + LLTrans::getString ("TimeDay") + "] ["
- + LLTrans::getString ("TimeHour") + "]:["
- + LLTrans::getString ("TimeMin") + "]";
+ timeStr = "[" + LLTrans::getString("TimeYear") + "]/["
+ + LLTrans::getString("TimeMonth") + "]/["
+ + LLTrans::getString("TimeDay") + "] ";
+ }
+
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ if (use_24h)
+ {
+ timeStr += "[" + LLTrans::getString("TimeHour") + "]:["
+ + LLTrans::getString("TimeMin") + "]";
}
else
{
- timeStr = "[" + LLTrans::getString("TimeHour") + "]:["
- + LLTrans::getString ("TimeMin")+"]";
+ timeStr += "[" + LLTrans::getString("TimeHour12") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeAMPM") + "]";
}
LLSD substitution;
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp
new file mode 100644
index 0000000000..9b6dcc5277
--- /dev/null
+++ b/indra/newview/llluamanager.cpp
@@ -0,0 +1,484 @@
+/**
+ * @file llluamanager.cpp
+ * @brief classes and functions for interfacing with LUA.
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ *
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llluamanager.h"
+
+#include "fsyspath.h"
+#include "llcoros.h"
+#include "llerror.h"
+#include "lleventcoro.h"
+#include "llsdutil.h"
+#include "llviewercontrol.h"
+#include "lua_function.h"
+#include "lualistener.h"
+#include "stringize.h"
+
+#include <boost/algorithm/string/replace.hpp>
+
+#include "luau/luacode.h"
+#include "luau/lua.h"
+#include "luau/luaconf.h"
+#include "luau/lualib.h"
+
+#include <sstream>
+#include <string_view>
+#include <vector>
+
+S32 LLLUAmanager::sAutorunScriptCount = 0;
+S32 LLLUAmanager::sScriptCount = 0;
+std::map<std::string, std::string> LLLUAmanager::sScriptNames;
+
+lua_function(sleep, "sleep(seconds): pause the running coroutine")
+{
+ lua_checkdelta(L, -1);
+ lua_Number seconds = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ llcoro::suspendUntilTimeout(narrow(seconds));
+ LuaState::getParent(L).set_interrupts_counter(0);
+ return 0;
+};
+
+// This function consumes ALL Lua stack arguments and returns concatenated
+// message string
+std::string lua_print_msg(lua_State* L, std::string_view level)
+{
+ // On top of existing Lua arguments, we're going to push tostring() and
+ // duplicate each existing stack entry so we can stringize each one.
+ lluau_checkstack(L, 2);
+ luaL_where(L, 1);
+ // start with the 'where' info at the top of the stack
+ std::string source_info{ lua_tostring(L, -1) };
+ lua_pop(L, 1);
+
+ std::ostringstream out;
+ const char* sep = ""; // 'where' info ends with ": "
+ // now iterate over arbitrary args, calling Lua tostring() on each and
+ // concatenating with separators
+ for (int p = 1, top = lua_gettop(L); p <= top; ++p)
+ {
+ out << sep;
+ sep = " ";
+ // push Lua tostring() function -- note, semantically different from
+ // lua_tostring()!
+ lua_getglobal(L, "tostring");
+ // Now the stack is arguments 1 .. N, plus tostring().
+ // Push a copy of the argument at index p.
+ lua_pushvalue(L, p);
+ // pop tostring() and arg-p, pushing tostring(arg-p)
+ // (ignore potential error code from lua_pcall() because, if there was
+ // an error, we expect the stack top to be an error message -- which
+ // we'll print)
+ lua_pcall(L, 1, 1, 0);
+ out << lua_tostring(L, -1);
+ lua_pop(L, 1);
+ }
+ // pop everything
+ lua_settop(L, 0);
+ // capture message string
+ std::string msg{ out.str() };
+ // put message out there for any interested party (*koff* LLFloaterLUADebug *koff*)
+ LLEventPumps::instance().obtain("lua output").post(llsd::map("msg", msg, "level", stringize(level, ": "), "source_info", source_info));
+
+ llcoro::suspend();
+ return source_info + msg;
+}
+
+lua_function(print_debug, "print_debug(args...): DEBUG level logging")
+{
+ LL_DEBUGS("Lua") << lua_print_msg(L, "DEBUG") << LL_ENDL;
+ return 0;
+}
+
+// also used for print(); see LuaState constructor
+lua_function(print_info, "print_info(args...): INFO level logging")
+{
+ LL_INFOS("Lua") << lua_print_msg(L, "INFO") << LL_ENDL;
+ return 0;
+}
+
+lua_function(print_warning, "print_warning(args...): WARNING level logging")
+{
+ LL_WARNS("Lua") << lua_print_msg(L, "WARN") << LL_ENDL;
+ return 0;
+}
+
+lua_function(post_on, "post_on(pumpname, data): post specified data to specified LLEventPump")
+{
+ lua_checkdelta(L, -2);
+ std::string pumpname{ lua_tostdstring(L, 1) };
+ LLSD data{ lua_tollsd(L, 2) };
+ lua_pop(L, 2);
+ LL_DEBUGS("Lua") << "post_on('" << pumpname << "', " << data << ")" << LL_ENDL;
+ LLEventPumps::instance().obtain(pumpname).post(data);
+ return 0;
+}
+
+lua_function(get_event_pumps,
+ "get_event_pumps():\n"
+ "Returns replypump, commandpump: names of LLEventPumps specific to this chunk.\n"
+ "Events posted to replypump are queued for get_event_next().\n"
+ "post_on(commandpump, ...) to engage LLEventAPI operations (see helpleap()).")
+{
+ lua_checkdelta(L, 2);
+ lluau_checkstack(L, 2);
+ auto& listener{ LuaState::obtainListener(L) };
+ // return the reply pump name and the command pump name on caller's lua_State
+ lua_pushstdstring(L, listener.getReplyName());
+ lua_pushstdstring(L, listener.getCommandName());
+ return 2;
+}
+
+lua_function(get_event_next,
+ "get_event_next():\n"
+ "Returns the next (pumpname, data) pair from the replypump whose name\n"
+ "is returned by get_event_pumps(). Blocks the calling chunk until an\n"
+ "event becomes available.")
+{
+ lua_checkdelta(L, 2);
+ lluau_checkstack(L, 2);
+ auto& listener{ LuaState::obtainListener(L) };
+ const auto& [pump, data]{ listener.getNext() };
+ lua_pushstdstring(L, pump);
+ lua_pushllsd(L, data);
+ LuaState::getParent(L).set_interrupts_counter(0);
+ return 2;
+}
+
+LLCoros::Future<LLLUAmanager::script_result>
+LLLUAmanager::startScriptFile(const std::string& filename)
+{
+ // Despite returning from startScriptFile(), we need this Promise to
+ // remain alive until the callback has fired.
+ auto promise{ std::make_shared<LLCoros::Promise<script_result>>() };
+ runScriptFile(filename, false,
+ [promise](int count, LLSD result)
+ { promise->set_value({ count, result }); });
+ return LLCoros::getFuture(*promise);
+}
+
+LLLUAmanager::script_result LLLUAmanager::waitScriptFile(const std::string& filename)
+{
+ return startScriptFile(filename).get();
+}
+
+void LLLUAmanager::runScriptFile(const std::string &filename, bool autorun,
+ script_result_fn result_cb)
+{
+ // A script_result_fn will be called when LuaState::expr() completes.
+ LLCoros::instance().launch(filename, [filename, autorun, result_cb]()
+ {
+ ScriptObserver observer(LLCoros::getName(), filename);
+ LLSD paths(gSavedSettings.getLLSD("LuaCommandPath"));
+ LL_DEBUGS("Lua") << "LuaCommandPath = " << paths << LL_ENDL;
+ // allow LuaCommandPath to be specified relative to install dir
+ ScriptCommand command(filename, paths, gDirUtilp->getAppRODataDir());
+ auto error = command.error();
+ if (! error.empty())
+ {
+ if (result_cb)
+ {
+ result_cb(-1, error);
+ }
+ return;
+ }
+
+ llifstream in_file;
+ in_file.open(command.script);
+ // At this point, since ScriptCommand did not report an error, we
+ // should be able to assume that 'script' exists. If we can't open it,
+ // something else is wrong?!
+ llassert(in_file.is_open());
+ if (autorun)
+ {
+ sAutorunScriptCount++;
+ }
+ sScriptCount++;
+
+ LuaState L;
+ std::string text{std::istreambuf_iterator<char>(in_file), {}};
+ auto [count, result] = L.expr(command.script, text, command.args);
+ if (result_cb)
+ {
+ result_cb(count, result);
+ }
+ });
+}
+
+LLCoros::Future<LLLUAmanager::script_result>
+LLLUAmanager::startScriptLine(const std::string& chunk)
+{
+ // Despite returning from startScriptLine(), we need this Promise to
+ // remain alive until the callback has fired.
+ auto promise{ std::make_shared<LLCoros::Promise<script_result>>() };
+ runScriptLine(chunk,
+ [promise](int count, LLSD result)
+ { promise->set_value({ count, result }); });
+ return LLCoros::getFuture(*promise);
+}
+
+LLLUAmanager::script_result LLLUAmanager::waitScriptLine(const std::string& chunk)
+{
+ return startScriptLine(chunk).get();
+}
+
+void LLLUAmanager::runScriptLine(const std::string& chunk, script_result_fn result_cb)
+{
+ // find a suitable abbreviation for the chunk string
+ std::string shortchunk{ chunk };
+ const size_t shortlen = 40;
+ std::string::size_type eol = shortchunk.find_first_of("\r\n");
+ if (eol != std::string::npos)
+ shortchunk = shortchunk.substr(0, eol);
+ if (shortchunk.length() > shortlen)
+ shortchunk = stringize(shortchunk.substr(0, shortlen), "...");
+
+ std::string desc{ "lua: " + shortchunk };
+ LLCoros::instance().launch(desc, [desc, chunk, result_cb]()
+ {
+ LuaState L;
+ auto [count, result] = L.expr(desc, chunk);
+ if (result_cb)
+ {
+ result_cb(count, result);
+ }
+ });
+}
+
+std::string read_file(const std::string &name)
+{
+ llifstream in_file;
+ in_file.open(name.c_str());
+
+ if (in_file.is_open())
+ {
+ return std::string{std::istreambuf_iterator<char>(in_file), {}};
+ }
+
+ return {};
+}
+
+lua_function(require, "require(module_name) : load module_name.lua from known places")
+{
+ lua_checkdelta(L);
+ std::string name = lua_tostdstring(L, 1);
+ lua_pop(L, 1);
+
+ // resolveRequire() does not return in case of error.
+ LLRequireResolver::resolveRequire(L, name);
+
+ // resolveRequire() returned the newly-loaded module on the stack top.
+ // Return it.
+ return 1;
+}
+
+// push loaded module or throw Lua error
+void LLRequireResolver::resolveRequire(lua_State *L, std::string path)
+{
+ LLRequireResolver resolver(L, std::move(path));
+ // findModule() pushes the loaded module or throws a Lua error.
+ resolver.findModule();
+}
+
+LLRequireResolver::LLRequireResolver(lua_State *L, const std::string& path) :
+ mPathToResolve(fsyspath(path).lexically_normal()),
+ L(L)
+{
+ mSourceDir = lluau::source_path(L).parent_path();
+
+ if (mPathToResolve.is_absolute())
+ luaL_argerrorL(L, 1, "cannot require a full path");
+}
+
+// push the loaded module or throw a Lua error
+void LLRequireResolver::findModule()
+{
+ // If mPathToResolve is absolute, this replaces mSourceDir.
+ fsyspath absolutePath(mSourceDir / mPathToResolve);
+
+ // Push _MODULES table on stack for checking and saving to the cache
+ luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1);
+ // Remove that stack entry no matter how we exit
+ LuaRemover rm_MODULES(L, -1);
+
+ // Check if the module is already in _MODULES table, read from file
+ // otherwise.
+ // findModuleImpl() pushes module if found, nothing if not, may throw Lua
+ // error.
+ if (findModuleImpl(absolutePath))
+ return;
+
+ // not already cached - prep error message just in case
+ auto fail{
+ [L=L, path=mPathToResolve.string()]()
+ { luaL_error(L, "could not find require('%s')", path.data()); }};
+
+ if (mPathToResolve.is_absolute())
+ {
+ // no point searching known directories for an absolute path
+ fail();
+ }
+
+ LLSD lib_paths(gSavedSettings.getLLSD("LuaRequirePath"));
+ LL_DEBUGS("Lua") << "LuaRequirePath = " << lib_paths << LL_ENDL;
+ for (const auto& path : llsd::inArray(lib_paths))
+ {
+ // if path is already absolute, operator/() preserves it
+ auto abspath(fsyspath(gDirUtilp->getAppRODataDir()) / path.asString());
+ fsyspath absolutePathOpt = (abspath / mPathToResolve);
+
+ if (absolutePathOpt.empty())
+ luaL_error(L, "error requiring module '%s'", mPathToResolve.string().data());
+
+ if (findModuleImpl(absolutePathOpt))
+ return;
+ }
+
+ // not found
+ fail();
+}
+
+// expects _MODULES table on stack top (and leaves it there)
+// - if found, pushes loaded module and returns true
+// - not found, pushes nothing and returns false
+// - may throw Lua error
+bool LLRequireResolver::findModuleImpl(const std::string& absolutePath)
+{
+ std::string possibleSuffixedPaths[] = {absolutePath + ".luau", absolutePath + ".lua"};
+
+ for (const auto& suffixedPath : possibleSuffixedPaths)
+ {
+ // Check _MODULES cache for module
+ lua_getfield(L, -1, suffixedPath.data());
+ if (!lua_isnil(L, -1))
+ {
+ return true;
+ }
+ lua_pop(L, 1);
+
+ // Try to read the matching file
+ std::string source = read_file(suffixedPath);
+ if (!source.empty())
+ {
+ // Try to run the loaded source. This will leave either a string
+ // error message or the module contents on the stack top.
+ runModule(suffixedPath, source);
+
+ // If the stack top is an error message string, raise it.
+ if (lua_isstring(L, -1))
+ lua_error(L);
+
+ // duplicate the new module: _MODULES newmodule newmodule
+ lua_pushvalue(L, -1);
+ // store _MODULES[found path] = newmodule
+ lua_setfield(L, -3, suffixedPath.data());
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// push string error message or new module
+void LLRequireResolver::runModule(const std::string& desc, const std::string& code)
+{
+ // Here we just loaded a new module 'code', need to run it and get its result.
+ lua_State *ML = lua_mainthread(L);
+
+ {
+ // If loadstring() returns (! LUA_OK) then there's an error message on
+ // the stack. If it returns LUA_OK then the newly-loaded module code
+ // is on the stack.
+ LL_DEBUGS("Lua") << "Loading module " << desc << LL_ENDL;
+ if (lluau::loadstring(ML, desc, code) != LUA_OK)
+ {
+ // error message on stack top
+ LL_DEBUGS("Lua") << "Error loading module " << desc << ": "
+ << lua_tostring(ML, -1) << LL_ENDL;
+ lua_pushliteral(ML, "loadstring: ");
+ // stack contains error, "loadstring: "
+ // swap: insert stack top at position -2
+ lua_insert(ML, -2);
+ // stack contains "loadstring: ", error
+ lua_concat(ML, 2);
+ // stack contains "loadstring: " + error
+ }
+ else // module code on stack top
+ {
+ // push debug module
+ lua_getglobal(ML, "debug");
+ // push debug.traceback
+ lua_getfield(ML, -1, "traceback");
+ // stack contains module code, debug, debug.traceback
+ // ditch debug
+ lua_replace(ML, -2);
+ // stack contains module code, debug.traceback
+ // swap: insert stack top at position -2
+ lua_insert(ML, -2);
+ // stack contains debug.traceback, module code
+ LL_DEBUGS("Lua") << "Loaded module " << desc << ", running" << LL_ENDL;
+ // no arguments, one return value
+ // pass debug.traceback as the error function
+ int status = lua_pcall(ML, 0, 1, -2);
+ // lua_pcall() has popped the module code and replaced it with its
+ // return value. Regardless of status or the type of the stack
+ // top, get rid of debug.traceback on the stack.
+ lua_remove(ML, -2);
+
+ if (status == LUA_OK)
+ {
+ auto top{ lua_gettop(ML) };
+ std::string type{ (top == 0)? "nothing"
+ : lua_typename(ML, lua_type(ML, -1)) };
+ LL_DEBUGS("Lua") << "Module " << desc << " returned " << type << LL_ENDL;
+ if ((top == 0) || ! (lua_istable(ML, -1) || lua_isfunction(ML, -1)))
+ {
+ lua_pushfstring(ML, "module %s must return a table or function, not %s",
+ desc.data(), type.data());
+ }
+ }
+ else if (status == LUA_YIELD)
+ {
+ LL_DEBUGS("Lua") << "Module " << desc << " yielded" << LL_ENDL;
+ lua_pushfstring(ML, "module %s can not yield", desc.data());
+ }
+ else
+ {
+ llassert(lua_isstring(ML, -1));
+ LL_DEBUGS("Lua") << "Module " << desc << " error: "
+ << lua_tostring(ML, -1) << LL_ENDL;
+ }
+ }
+ }
+ // There's now a return value (string error message or module) on top of ML.
+ // Move return value to L's stack.
+ if (ML != L)
+ {
+ lua_xmove(ML, L, 1);
+ }
+}
diff --git a/indra/newview/llluamanager.h b/indra/newview/llluamanager.h
new file mode 100644
index 0000000000..b98b5d4ef6
--- /dev/null
+++ b/indra/newview/llluamanager.h
@@ -0,0 +1,133 @@
+/**
+ * @file llluamanager.h
+ * @brief classes and functions for interfacing with LUA.
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLLUAMANAGER_H
+#define LL_LLLUAMANAGER_H
+
+#include "fsyspath.h"
+#include "llcoros.h"
+#include "llsd.h"
+#include <functional>
+#include <string>
+#include <utility> // std::pair
+
+#include "luau/lua.h"
+#include "luau/lualib.h"
+
+class LuaState;
+
+class LLLUAmanager
+{
+ friend class ScriptObserver;
+
+public:
+ // Pass a callback with this signature to obtain the result, if any, of
+ // running a script or source string.
+ // count < 0 means error, and result.asString() is the error message.
+ // count == 0 with result.isUndefined() means the script returned no results.
+ // count == 1 means the script returned one result.
+ // count > 1 with result.isArray() means the script returned multiple
+ // results, represented as the entries of the result array.
+ typedef std::function<void(int count, const LLSD& result)> script_result_fn;
+ // same semantics as script_result_fn parameters
+ typedef std::pair<int, LLSD> script_result;
+
+ // Run the script specified by the command line passed as @a filename.
+ // This can be followed by some number of command-line arguments, which
+ // a Lua script can view using either '...' or predefined global 'arg'.
+ // The script pathname or its arguments can be quoted using 'single
+ // quotes' or "double quotes", or special characters can be \escaped.
+ // runScriptFile() recognizes the case in which the whole 'filename'
+ // string is a path containing spaces; if so no arguments are permitted.
+ // In either form, if the script pathname isn't absolute, it is sought on
+ // LuaCommandPath.
+ // If autorun is true, statistics will count this as an autorun script.
+ static void runScriptFile(const std::string &filename, bool autorun = false,
+ script_result_fn result_cb = {});
+ // Start running a Lua script file, returning an LLCoros::Future whose
+ // get() method will pause the calling coroutine until it can deliver the
+ // (count, result) pair described above. Between startScriptFile() and
+ // Future::get(), the caller and the Lua script coroutine will run
+ // concurrently.
+ // @a filename is as described for runScriptFile().
+ static LLCoros::Future<script_result> startScriptFile(const std::string& filename);
+ // Run a Lua script file, and pause the calling coroutine until it completes.
+ // The return value is the (count, result) pair described above.
+ // @a filename is as described for runScriptFile().
+ static script_result waitScriptFile(const std::string& filename);
+
+ static void runScriptLine(const std::string &chunk, script_result_fn result_cb = {});
+ // Start running a Lua chunk, returning an LLCoros::Future whose
+ // get() method will pause the calling coroutine until it can deliver the
+ // (count, result) pair described above. Between startScriptLine() and
+ // Future::get(), the caller and the Lua script coroutine will run
+ // concurrently.
+ static LLCoros::Future<script_result> startScriptLine(const std::string& chunk);
+ // Run a Lua chunk, and pause the calling coroutine until it completes.
+ // The return value is the (count, result) pair described above.
+ static script_result waitScriptLine(const std::string& chunk);
+
+ static const std::map<std::string, std::string> getScriptNames() { return sScriptNames; }
+
+ static S32 sAutorunScriptCount;
+ static S32 sScriptCount;
+
+ private:
+ static std::map<std::string, std::string> sScriptNames;
+};
+
+class LLRequireResolver
+{
+ public:
+ static void resolveRequire(lua_State *L, std::string path);
+
+ private:
+ fsyspath mPathToResolve;
+ fsyspath mSourceDir;
+
+ LLRequireResolver(lua_State *L, const std::string& path);
+
+ void findModule();
+ lua_State *L;
+
+ bool findModuleImpl(const std::string& absolutePath);
+ void runModule(const std::string& desc, const std::string& code);
+};
+
+// RAII class to guarantee that a script entry is erased even when coro is terminated
+class ScriptObserver
+{
+ public:
+ ScriptObserver(const std::string &coro_name, const std::string &filename) : mCoroName(coro_name)
+ {
+ LLLUAmanager::sScriptNames[mCoroName] = filename;
+ }
+ ~ScriptObserver() { LLLUAmanager::sScriptNames.erase(mCoroName); }
+
+ private:
+ std::string mCoroName;
+};
+#endif
diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp
index 3fdf7bd925..8bcfaa36e8 100644
--- a/indra/newview/llmanip.cpp
+++ b/indra/newview/llmanip.cpp
@@ -519,9 +519,9 @@ void LLManip::renderTickText(const LLVector3& pos, const std::string& text, cons
LLColor4 shadow_color = LLColor4::black;
shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f;
gViewerWindow->setup3DViewport(1, -1);
- hud_render_utf8text(text, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(text), 3.f, shadow_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD);
+ hud_render_utf8text(text, render_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(text), 3.f, shadow_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD);
gViewerWindow->setup3DViewport();
- hud_render_utf8text(text, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(text), 3.f, color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD);
+ hud_render_utf8text(text, render_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(text), 3.f, color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD);
gGL.popMatrix();
}
@@ -578,12 +578,12 @@ void LLManip::renderTickValue(const LLVector3& pos, F32 value, const std::string
{
fraction_string = llformat("%c%02d%s", LLResMgr::getInstance()->getDecimalPoint(), fractional_portion, suffix.c_str());
- hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, -1.f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection);
- hud_render_utf8text(fraction_string, render_pos, *small_fontp, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, 1.f, 3.f, color, hud_selection);
+ hud_render_utf8text(val_string, render_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, -1.f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection);
+ hud_render_utf8text(fraction_string, render_pos, nullptr, *small_fontp, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, 1.f, 3.f, color, hud_selection);
}
else
{
- hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, -0.5f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection);
+ hud_render_utf8text(val_string, render_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, -0.5f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection);
}
}
gGL.popMatrix();
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index b63b8be095..7642a76308 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -1171,10 +1171,10 @@ void LLManipRotate::renderSnapGuides()
std::string help_text = LLTrans::getString("manip_hint1");
LLColor4 help_text_color = LLColor4::white;
help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f);
- hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ hud_render_utf8text(help_text, help_text_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
help_text = LLTrans::getString("manip_hint2");
help_text_pos -= offset_dir * mRadiusMeters * 0.4f;
- hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ hud_render_utf8text(help_text, help_text_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
}
}
}
diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp
index 66420d1cad..9966a8eedb 100644
--- a/indra/newview/llmanipscale.cpp
+++ b/indra/newview/llmanipscale.cpp
@@ -1844,10 +1844,10 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox)
std::string help_text = LLTrans::getString("manip_hint1");
LLColor4 help_text_color = LLColor4::white;
help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, grid_alpha, 0.f);
- hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ hud_render_utf8text(help_text, help_text_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
help_text = LLTrans::getString("manip_hint2");
help_text_pos -= LLViewerCamera::getInstance()->getUpAxis() * mSnapRegimeOffset * 0.4f;
- hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ hud_render_utf8text(help_text, help_text_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
}
}
}
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 0888f630e8..060fe0d600 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -1449,10 +1449,10 @@ void LLManipTranslate::renderSnapGuides()
std::string help_text = LLTrans::getString("manip_hint1");
LLColor4 help_text_color = LLColor4::white;
help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f);
- hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ hud_render_utf8text(help_text, help_text_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
help_text = LLTrans::getString("manip_hint2");
help_text_pos -= LLViewerCamera::getInstance()->getUpAxis() * mSnapOffsetMeters * 0.2f;
- hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ hud_render_utf8text(help_text, help_text_pos, nullptr, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
}
}
}
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index dde238eddb..355fb78ad2 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -63,8 +63,9 @@
#include "tinygltf/tiny_gltf.h"
#include "lltinygltfhelper.h"
-#include <strstream>
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
const std::string MATERIAL_BASE_COLOR_DEFAULT_NAME = "Base Color";
const std::string MATERIAL_NORMAL_DEFAULT_NAME = "Normal";
@@ -1245,7 +1246,7 @@ bool LLMaterialEditor::decodeAsset(const std::vector<char>& buffer)
{
LLSD asset;
- std::istrstream str(&buffer[0], buffer.size());
+ boost::iostreams::stream<boost::iostreams::array_source> str(buffer.data(), buffer.size());
if (LLSDSerialize::deserialize(asset, str, buffer.size()))
{
if (asset.has("version") && LLGLTFMaterial::isAcceptedVersion(asset["version"].asString()))
@@ -1414,7 +1415,7 @@ bool LLMaterialEditor::saveIfNeeded()
}
std::string res_desc = buildMaterialDescription();
- createInventoryItem(buffer, mMaterialName, res_desc, local_permissions);
+ createInventoryItem(buffer, mMaterialName, res_desc, local_permissions, mUploadFolder);
// We do not update floater with uploaded asset yet, so just close it.
closeFloater();
@@ -1584,12 +1585,12 @@ private:
std::string mNewName;
};
-void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions)
+void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions, const LLUUID& upload_folder)
{
// gen a new uuid for this asset
LLTransactionID tid;
tid.generate(); // timestamp-based randomization + uniquification
- LLUUID parent = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL);
+ LLUUID parent = upload_folder.isNull() ? gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL) : upload_folder;
const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ?
LLPointer<LLObjectsMaterialItemCallback> cb = new LLObjectsMaterialItemCallback(permissions, buffer, name);
@@ -1903,7 +1904,11 @@ static void pack_textures(
}
}
-void LLMaterialEditor::uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model_in, S32 index)
+void LLMaterialEditor::uploadMaterialFromModel(
+ const std::string& filename,
+ tinygltf::Model& model_in,
+ S32 index,
+ const LLUUID& dest)
{
if (index < 0 || !LLMaterialEditor::capabilitiesAvailable())
{
@@ -1926,12 +1931,13 @@ void LLMaterialEditor::uploadMaterialFromModel(const std::string& filename, tiny
// This uses 'filename' to make sure multiple bulk uploads work
// instead of fighting for a single instance.
LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor", LLSD().with("filename", filename).with("index", LLSD::Integer(index)));
+ me->mUploadFolder = dest;
me->loadMaterial(model_in, filename, index, false);
me->saveIfNeeded();
}
-void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index)
+void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index, const LLUUID& dest_folder)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
@@ -1977,6 +1983,7 @@ void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 ind
}
LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor");
+ me->mUploadFolder = dest_folder;
if (index >= 0)
{
@@ -2427,17 +2434,18 @@ void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notificati
return;
}
- createInventoryItem(str.str(), new_name, std::string(), permissions);
+ createInventoryItem(str.str(), new_name, std::string(), permissions, LLUUID::null);
}
-const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type, bool allow_2k);
+
+void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type, bool allow_2k, const LLUUID& dest);
void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::string &filename, S32 index, bool open_floater)
{
if (index == model_in.materials.size())
{
// bulk upload all the things
- upload_bulk({ filename }, LLFilePicker::FFLOAD_MATERIAL, true);
+ upload_bulk({ filename }, LLFilePicker::FFLOAD_MATERIAL, true, LLUUID::null);
return;
}
@@ -2844,10 +2852,10 @@ void LLMaterialEditor::setFromGltfMetaData(const std::string& filename, const ti
}
}
-void LLMaterialEditor::importMaterial()
+void LLMaterialEditor::importMaterial(const LLUUID dest_folder)
{
LLFilePickerReplyThread::startPicker(
- [](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
+ [dest_folder](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
{
if (LLAppViewer::instance()->quitRequested())
{
@@ -2855,7 +2863,7 @@ void LLMaterialEditor::importMaterial()
}
if (filenames.size() > 0)
{
- LLMaterialEditor::loadMaterialFromFile(filenames[0], -1);
+ LLMaterialEditor::loadMaterialFromFile(filenames[0], -1, dest_folder);
}
},
LLFilePicker::FFLOAD_MATERIAL,
@@ -3538,6 +3546,7 @@ void LLMaterialEditor::saveTexture(LLImageJ2C* img, const std::string& name, con
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
expected_upload_cost,
+ mUploadFolder,
false,
cb,
failed_upload));
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index 232467460e..1abdd7f84c 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -94,7 +94,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
void setFromGltfMetaData(const std::string& filename, const tinygltf::Model& model, S32 index);
// open a file dialog and select a gltf/glb file for import
- static void importMaterial();
+ static void importMaterial(const LLUUID dest_folder = LLUUID::null);
// for live preview, apply current material to currently selected object
void applyToSelection();
@@ -105,8 +105,11 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
void loadAsset() override;
// @index if -1 and file contains more than one material,
// will promt to select specific one
- static void uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model, S32 index);
- static void loadMaterialFromFile(const std::string& filename, S32 index = -1);
+ static void uploadMaterialFromModel(const std::string& filename,
+ tinygltf::Model& model,
+ S32 index,
+ const LLUUID& dest_folder_id = LLUUID::null);
+ static void loadMaterialFromFile(const std::string& filename, S32 index = -1, const LLUUID& dest_folder = LLUUID::null);
void onSelectionChanged(); // live overrides selection changes
@@ -134,8 +137,6 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
void onClickSave();
- void getGLTFModel(tinygltf::Model& model);
-
std::string getEncodedAsset();
bool decodeAsset(const std::vector<char>& buffer);
@@ -239,7 +240,7 @@ private:
static void saveObjectsMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions, const LLUUID& object_id /* = LLUUID::null */, const LLUUID& item /* = LLUUID::null */);
static bool updateInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id);
- static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions);
+ static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions, const LLUUID& upload_folder);
void setFromGLTFMaterial(LLGLTFMaterial* mat);
bool setFromSelection();
@@ -249,6 +250,7 @@ private:
friend class LLMaterialFilePicker;
LLUUID mAssetID;
+ LLUUID mUploadFolder;
LLTextureCtrl* mBaseColorTextureCtrl;
LLTextureCtrl* mMetallicTextureCtrl;
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 202008f7f9..49260d5c50 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -345,8 +345,8 @@ bool LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )
auto menu = mContextMenuHandle.get();
if (!menu)
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar;
- registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this));
+ LLUICtrl::ScopedRegistrarHelper registrar;
+ registrar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this));
// stinson 05/05/2014 : use this as the parent of the context menu if the static menu
// container has yet to be created
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index ca035e79e0..a5e6e43e3f 100644
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -219,7 +219,7 @@ protected:
{
public:
RetryTimer(F32 time, Request::ptr_t);
- virtual bool tick();
+ bool tick() override;
private:
// back-pointer
Request::ptr_t mRequest;
@@ -286,7 +286,7 @@ private:
{
public:
QueueTimer(F32 time, LLMediaDataClient *mdc);
- virtual bool tick();
+ bool tick() override;
private:
// back-pointer
LLPointer<LLMediaDataClient> mMDC;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index a5bed1dbe6..f4b6f9bee9 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -548,8 +548,8 @@ LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMate
return ppTex ? (*ppTex).get() : NULL;
}
-volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
-volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;
+std::atomic<S32> LLMeshRepoThread::sActiveHeaderRequests = 0;
+std::atomic<S32> LLMeshRepoThread::sActiveLODRequests = 0;
U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
S32 LLMeshRepoThread::sRequestLowWater = REQUEST2_LOW_WATER_MIN;
S32 LLMeshRepoThread::sRequestHighWater = REQUEST2_HIGH_WATER_MIN;
@@ -742,8 +742,12 @@ public:
};
-void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
- const char * const stage, const std::string & model_name)
+void log_upload_error(
+ LLCore::HttpStatus status,
+ const LLSD& content,
+ const char * const stage,
+ const std::string & model_name,
+ const std::vector<std::string> & texture_filenames)
{
// Add notification popup.
LLSD args;
@@ -801,6 +805,20 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
error_num++;
}
}
+
+ if (err.has("TextureIndex"))
+ {
+ S32 texture_index = err["TextureIndex"].asInteger();
+ if (texture_index < texture_filenames.size())
+ {
+ args["MESSAGE"] = message + "\n" + texture_filenames[texture_index];
+ }
+ else
+ {
+ llassert(false); // figure out why or how texture wasn't in the list
+ args["MESSAGE"] = message + llformat("\nTexture index: %d", texture_index);
+ }
+ }
}
else
{
@@ -2158,7 +2176,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_
LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
- const std::string & upload_url, bool do_upload,
+ const std::string & upload_url, LLUUID destination_folder_id, bool do_upload,
LLHandle<LLWholeModelFeeObserver> fee_observer,
LLHandle<LLWholeModelUploadObserver> upload_observer)
: LLThread("mesh upload"),
@@ -2166,6 +2184,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
mDiscarded(false),
mDoUpload(do_upload),
mWholeModelUploadURL(upload_url),
+ mDestinationFolderId(destination_folder_id),
mFeeObserverHandle(fee_observer),
mUploadObserverHandle(upload_observer)
{
@@ -2283,13 +2302,21 @@ LLSD llsd_from_file(std::string filename)
return result;
}
-void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
+void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>& texture_list_dest, bool include_textures)
{
LLSD result;
LLSD res;
- result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT);
- result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE);
+ if (mDestinationFolderId.isNull())
+ {
+ result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE);
+ }
+ else
+ {
+ result["folder_id"] = mDestinationFolderId;
+ result["texture_folder_id"] = mDestinationFolderId;
+ }
result["asset_type"] = "mesh";
result["inventory_type"] = "object";
result["description"] = "(No Description)";
@@ -2432,7 +2459,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
LLPointer<LLImageJ2C> upload_file =
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
- if (!upload_file.isNull() && upload_file->getDataSize())
+ if (!upload_file.isNull() && upload_file->getDataSize() && !upload_file->isBufferInvalid())
{
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
}
@@ -2446,6 +2473,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
texture_index[texture] = texture_num;
std::string str = texture_str.str();
res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
+ // store indexes for error handling;
+ texture_list_dest.push_back(material.mDiffuseMapFilename);
texture_num++;
}
@@ -2710,7 +2739,8 @@ void LLMeshUploadThread::doWholeModelUpload()
LL_DEBUGS(LOG_MESH) << "Hull generation completed." << LL_ENDL;
mModelData = LLSD::emptyMap();
- wholeModelToLLSD(mModelData, true);
+ mTextureFiles.clear();
+ wholeModelToLLSD(mModelData, mTextureFiles, true);
LLSD body = mModelData["asset_resources"];
dump_llsd_to_file(body, make_dump_name("whole_model_body_", dump_num));
@@ -2763,7 +2793,8 @@ void LLMeshUploadThread::requestWholeModelFee()
generateHulls();
mModelData = LLSD::emptyMap();
- wholeModelToLLSD(mModelData, false);
+ mTextureFiles.clear();
+ wholeModelToLLSD(mModelData, mTextureFiles, false);
dump_llsd_to_file(mModelData, make_dump_name("whole_model_fee_request_", dump_num));
LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
mHttpPolicyClass,
@@ -2829,7 +2860,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
body["error"] = LLSD::emptyMap();
body["error"]["message"] = reason;
body["error"]["identifier"] = "NetworkError"; // from asset-upload/upload_util.py
- log_upload_error(status, body, "upload", mModelData["name"].asString());
+ log_upload_error(status, body, "upload", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@@ -2864,7 +2895,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
else
{
LL_WARNS(LOG_MESH) << "Upload failed. Not in expected 'complete' state." << LL_ENDL;
- log_upload_error(status, body, "upload", mModelData["name"].asString());
+ log_upload_error(status, body, "upload", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@@ -2889,7 +2920,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
body["error"] = LLSD::emptyMap();
body["error"]["message"] = reason;
body["error"]["identifier"] = "NetworkError"; // from asset-upload/upload_util.py
- log_upload_error(status, body, "fee", mModelData["name"].asString());
+ log_upload_error(status, body, "fee", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@@ -2922,7 +2953,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp
else
{
LL_WARNS(LOG_MESH) << "Fee request failed. Not in expected 'upload' state." << LL_ENDL;
- log_upload_error(status, body, "fee", mModelData["name"].asString());
+ log_upload_error(status, body, "fee", mModelData["name"].asString(), mTextureFiles);
if (observer)
{
@@ -3694,20 +3725,63 @@ S32 LLMeshRepository::update()
return static_cast<S32>(size);
}
-void LLMeshRepository::unregisterMesh(LLVOVolume* vobj)
+void LLMeshRepository::unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail)
{
- for (auto& lod : mLoadingMeshes)
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+
+ llassert((mesh_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
+ llassert(mesh_params.getSculptID().notNull());
+ auto& lod = mLoadingMeshes[detail];
+ auto param_iter = lod.find(mesh_params.getSculptID());
+ if (param_iter != lod.end())
{
- for (auto& param : lod)
+ vector_replace_with_last(param_iter->second, vobj);
+ llassert(!vector_replace_with_last(param_iter->second, vobj));
+ if (param_iter->second.empty())
{
- vector_replace_with_last(param.second, vobj);
+ lod.erase(param_iter);
}
}
+}
+
+void LLMeshRepository::unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
- for (auto& skin_pair : mLoadingSkins)
+ llassert(mesh_id.notNull());
+ auto skin_pair_iter = mLoadingSkins.find(mesh_id);
+ if (skin_pair_iter != mLoadingSkins.end())
+ {
+ vector_replace_with_last(skin_pair_iter->second, vobj);
+ llassert(!vector_replace_with_last(skin_pair_iter->second, vobj));
+ if (skin_pair_iter->second.empty())
+ {
+ mLoadingSkins.erase(skin_pair_iter);
+ }
+ }
+}
+
+// Lots of dead objects make expensive calls to
+// LLMeshRepository::unregisterMesh which may delay shutdown. Avoid this by
+// preemptively unregistering all meshes.
+// We can also do this safely if all objects are confirmed dead for some other
+// reason.
+void LLMeshRepository::unregisterAllMeshes()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+
+ // The size of mLoadingMeshes and mLoadingSkins may be large and thus
+ // expensive to iterate over in LLVOVolume::~LLVOVolume.
+ // This is unnecessary during shutdown, so we ignore the referenced objects in the
+ // least expensive way which is still safe: by clearing these containers.
+ // Clear now and not in LLMeshRepository::shutdown because
+ // LLMeshRepository::notifyLoadedMeshes could (depending on invocation
+ // order) reference a pointer to an object after it has been deleted.
+ for (auto& lod : mLoadingMeshes)
{
- vector_replace_with_last(skin_pair.second, vobj);
+ lod.clear();
}
+ mLoadingSkins.clear();
}
S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
@@ -3916,7 +3990,7 @@ void LLMeshRepository::notifyLoadedMeshes()
}
// erase from background thread
- mThread->mWorkQueue.post([=]()
+ mThread->mWorkQueue.post([=, this]()
{
mThread->mSkinMap.erase(id);
});
@@ -4410,12 +4484,12 @@ bool LLMeshRepoThread::hasHeader(const LLUUID& mesh_id)
void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
- std::string upload_url, bool do_upload,
+ std::string upload_url, const LLUUID& destination_folder_id, bool do_upload,
LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
{
LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures,
upload_skin, upload_joints, lock_scale_if_joint_position,
- upload_url, do_upload, fee_observer, upload_observer);
+ upload_url, destination_folder_id, do_upload, fee_observer, upload_observer);
mUploadWaitList.push_back(thread);
}
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index b5c2424578..51b19207d9 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -256,8 +256,8 @@ class LLMeshRepoThread : public LLThread
{
public:
- volatile static S32 sActiveHeaderRequests;
- volatile static S32 sActiveLODRequests;
+ static std::atomic<S32> sActiveHeaderRequests;
+ static std::atomic<S32> sActiveLODRequests;
static U32 sMaxConcurrentRequests;
static S32 sRequestLowWater;
static S32 sRequestHighWater;
@@ -510,10 +510,13 @@ public:
LLHost mHost;
std::string mWholeModelFeeCapability;
std::string mWholeModelUploadURL;
+ LLUUID mDestinationFolderId;
LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
- const std::string & upload_url, bool do_upload = true,
+ const std::string & upload_url,
+ const LLUUID destination_folder_id = LLUUID::null,
+ bool do_upload = true,
LLHandle<LLWholeModelFeeObserver> fee_observer = (LLHandle<LLWholeModelFeeObserver>()),
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
~LLMeshUploadThread();
@@ -529,7 +532,7 @@ public:
void doWholeModelUpload();
void requestWholeModelFee();
- void wholeModelToLLSD(LLSD& dest, bool include_textures);
+ void wholeModelToLLSD(LLSD& dest, std::vector<std::string>& texture_list_dest, bool include_textures);
void decomposeMeshMatrix(LLMatrix4& transformation,
LLVector3& result_pos,
@@ -550,6 +553,7 @@ private:
bool mDoUpload; // if false only model data will be requested, otherwise the model will be uploaded
LLSD mModelData;
+ std::vector<std::string> mTextureFiles;
// llcorehttp library interface objects.
LLCore::HttpStatus mHttpStatus;
@@ -641,10 +645,12 @@ public:
LLMeshRepository();
void init();
+ void unregisterAllMeshes();
void shutdown();
S32 update();
- void unregisterMesh(LLVOVolume* volume);
+ void unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail);
+ void unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj);
//mesh management functions
S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
@@ -672,7 +678,9 @@ public:
void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
- std::string upload_url, bool do_upload = true,
+ std::string upload_url,
+ const LLUUID& destination_folder_id = LLUUID::null,
+ bool do_upload = true,
LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()),
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 7de16e0056..07e19c4c6c 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2344,7 +2344,7 @@ void LLModelPreview::updateStatusMessages()
if (lod != lod_high)
{
- if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high])
+ if (total_submeshes[lod] && total_submeshes[lod] > total_submeshes[lod_high])
{ //number of submeshes is different
message = "mesh_status_submesh_mismatch";
upload_status[lod] = 2;
@@ -3322,7 +3322,6 @@ bool LLModelPreview::render()
fmp->setViewOptionEnabled("show_skin_weight", show_skin_weight);
}
}
- //if (this) return TRUE;
if (upload_skin && !has_skin_weights)
{ //can't upload skin weights if model has no skin weights
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index af472c4259..483ddcdd63 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -128,7 +128,7 @@ LLNetMap::~LLNetMap()
bool LLNetMap::postBuild()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commitRegistrar;
+ LLUICtrl::ScopedRegistrarHelper commitRegistrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enableRegistrar;
enableRegistrar.add("Minimap.Zoom.Check", boost::bind(&LLNetMap::isZoomChecked, this, _2));
diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp
index 5b8b28ebe6..9a33bcb1b9 100644
--- a/indra/newview/llnotificationlistitem.cpp
+++ b/indra/newview/llnotificationlistitem.cpp
@@ -38,6 +38,7 @@
#include "lluicolortable.h"
#include "message.h"
#include "llnotificationsutil.h"
+#include "llviewercontrol.h"
#include <boost/regex.hpp>
LLNotificationListItem::LLNotificationListItem(const Params& p) : LLPanel(p),
@@ -133,10 +134,22 @@ std::string LLNotificationListItem::buildNotificationDate(const LLDate& time_sta
default:
timeStr = "[" + LLTrans::getString("TimeMonth") + "]/["
+LLTrans::getString("TimeDay")+"]/["
- +LLTrans::getString("TimeYear")+"] ["
- +LLTrans::getString("TimeHour")+"]:["
- +LLTrans::getString("TimeMin")+"] ["
- +LLTrans::getString("TimeTimezone")+"]";
+ +LLTrans::getString("TimeYear")+"] [";
+
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ if (use_24h)
+ {
+ timeStr += LLTrans::getString("TimeHour") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeTimezone") + "]";
+ }
+ else
+ {
+ timeStr += LLTrans::getString("TimeHour12") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeAMPM") + "] ["
+ + LLTrans::getString("TimeTimezone") + "]";
+ }
break;
}
LLSD substitution;
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 72fb9464d8..489be091d1 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -81,9 +81,16 @@ LLOutfitGallery::LLOutfitGallery(const LLOutfitGallery::Params& p)
mItemsInRow(p.items_in_row),
mRowPanWidthFactor(p.row_panel_width_factor),
mGalleryWidthFactor(p.gallery_width_factor),
- mTextureSelected(NULL)
+ mTextureSelected(NULL),
+ mSortMenu(nullptr)
{
updateGalleryWidth();
+
+ LLControlVariable* ctrl = gSavedSettings.getControl("InventoryFavoritesColorText");
+ if (ctrl)
+ {
+ mSavedSettingInvFavColor = ctrl->getSignal()->connect(boost::bind(&LLOutfitGallery::handleInvFavColorChange, this));
+ }
}
LLOutfitGallery::Params::Params()
@@ -414,19 +421,28 @@ void LLOutfitGallery::updateRowsIfNeeded()
bool compareGalleryItem(LLOutfitGalleryItem* item1, LLOutfitGalleryItem* item2)
{
- static LLCachedControl<bool> outfit_gallery_sort_by_name(gSavedSettings, "OutfitGallerySortByName");
- if(outfit_gallery_sort_by_name ||
- ((item1->isDefaultImage() && item2->isDefaultImage()) || (!item1->isDefaultImage() && !item2->isDefaultImage())))
- {
- std::string name1 = item1->getItemName();
- std::string name2 = item2->getItemName();
-
- return (LLStringUtil::compareDict(name1, name2) < 0);
- }
- else
+ static LLCachedControl<S32> sort_by_name(gSavedSettings, "OutfitGallerySortOrder", 0);
+ switch (sort_by_name())
{
- return item2->isDefaultImage();
+ case 2:
+ if (item1->isFavorite() != item2->isFavorite())
+ {
+ return item1->isFavorite();
+ }
+ break;
+ case 1:
+ if (item1->isDefaultImage() != item2->isDefaultImage())
+ {
+ return item2->isDefaultImage();
+ }
+ break;
+ default:
+ break;
}
+
+ std::string name1 = item1->getItemName();
+ std::string name2 = item2->getItemName();
+ return (LLStringUtil::compareDict(name1, name2) < 0);
}
void LLOutfitGallery::reArrangeRows(S32 row_diff)
@@ -469,6 +485,20 @@ void LLOutfitGallery::updateGalleryWidth()
mGalleryWidth = mGalleryWidthFactor * mItemsInRow - mItemHorizontalGap;
}
+void LLOutfitGallery::handleInvFavColorChange()
+{
+ for (outfit_map_t::iterator iter = mOutfitMap.begin();
+ iter != mOutfitMap.end();
+ ++iter)
+ {
+ if (!iter->second) continue;
+ LLOutfitGalleryItem* item = (LLOutfitGalleryItem*)iter->second;
+
+ // refresh font color
+ item->setOutfitFavorite(item->isFavorite());
+ }
+}
+
LLPanel* LLOutfitGallery::addLastRow()
{
mRowCount++;
@@ -620,7 +650,7 @@ void LLOutfitGallery::removeFromLastRow(LLOutfitGalleryItem* item)
mItemPanels.pop_back();
}
-LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID outfit_id)
+LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID outfit_id, bool is_favorite)
{
LLOutfitGalleryItem::Params giparams;
LLOutfitGalleryItem* gitem = LLUICtrlFactory::create<LLOutfitGalleryItem>(giparams);
@@ -629,6 +659,7 @@ LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID
gitem->setFollowsLeft();
gitem->setFollowsTop();
gitem->setOutfitName(name);
+ gitem->setOutfitFavorite(is_favorite);
gitem->setUUID(outfit_id);
gitem->setGallery(this);
return gitem;
@@ -786,8 +817,7 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id)
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
if (!cat) return;
- std::string name = cat->getName();
- LLOutfitGalleryItem* item = buildGalleryItem(name, cat_id);
+ LLOutfitGalleryItem* item = buildGalleryItem(cat->getName(), cat_id, cat->getIsFavorite());
mOutfitMap.insert(LLOutfitGallery::outfit_map_value_t(cat_id, item));
item->setRightMouseDownCallback(boost::bind(&LLOutfitListBase::outfitRightClickCallBack, this,
_1, _2, _3, cat_id));
@@ -856,6 +886,7 @@ void LLOutfitGallery::updateChangedCategoryName(LLViewerInventoryCategory *cat,
if (item)
{
item->setOutfitName(name);
+ item->setOutfitFavorite(cat->getIsFavorite());
}
}
}
@@ -936,6 +967,10 @@ LLOutfitListGearMenuBase* LLOutfitGallery::createGearMenu()
static LLDefaultChildRegistry::Register<LLOutfitGalleryItem> r("outfit_gallery_item");
+bool LLOutfitGalleryItem::sColorSetInitialized = false;
+LLUIColor LLOutfitGalleryItem::sDefaultTextColor;
+LLUIColor LLOutfitGalleryItem::sDefaultFavoriteColor;
+
LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p)
: LLPanel(p),
mGallery(nullptr),
@@ -947,6 +982,12 @@ LLOutfitGalleryItem::LLOutfitGalleryItem(const Params& p)
mUUID(LLUUID())
{
buildFromFile("panel_outfit_gallery_item.xml");
+ if (!sColorSetInitialized)
+ {
+ sDefaultTextColor = LLUIColorTable::instance().getColor("White", LLColor4::white);
+ sDefaultFavoriteColor = LLUIColorTable::instance().getColor("InventoryFavoriteColor", LLColor4::white);
+ sColorSetInitialized = true;
+ }
}
LLOutfitGalleryItem::~LLOutfitGalleryItem()
@@ -1003,6 +1044,18 @@ void LLOutfitGalleryItem::draw()
}
}
+ static LLUICachedControl<bool> draw_star("InventoryFavoritesUseStar", true);
+ if(mFavorite && draw_star())
+ {
+ const S32 HPAD = 3;
+ const S32 VPAD = 6; // includes padding for text and for the image
+ const S32 image_size = 14;
+ static LLPointer<LLUIImage> fav_img = LLRender2D::getInstance()->getUIImage("Inv_Favorite_Star_Full");
+
+ gl_draw_scaled_image(
+ border.getWidth() - image_size - HPAD, image_size + VPAD + mOutfitNameText->getRect().getHeight(),
+ image_size, image_size, fav_img->getImage(), UI_VERTEX_COLOR % alpha);
+ }
}
void LLOutfitGalleryItem::setOutfitName(std::string name)
@@ -1012,18 +1065,27 @@ void LLOutfitGalleryItem::setOutfitName(std::string name)
mOutfitName = name;
}
+void LLOutfitGalleryItem::setOutfitFavorite(bool is_favorite)
+{
+ mFavorite = is_favorite;
+
+ static LLCachedControl<bool> use_color(gSavedSettings, "InventoryFavoritesColorText");
+ mOutfitNameText->setReadOnlyColor((mFavorite && use_color()) ? sDefaultFavoriteColor.get() : sDefaultTextColor.get());
+}
+
void LLOutfitGalleryItem::setOutfitWorn(bool value)
{
mWorn = value;
LLStringUtil::format_map_t worn_string_args;
std::string worn_string = getString("worn_string", worn_string_args);
- LLUIColor text_color = LLUIColorTable::instance().getColor("White", LLColor4::white);
- mOutfitWornText->setReadOnlyColor(text_color);
- mOutfitNameText->setReadOnlyColor(text_color);
+ mOutfitWornText->setReadOnlyColor(sDefaultTextColor.get());
mOutfitWornText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
mOutfitNameText->setFont(value ? LLFontGL::getFontSansSerifBold() : LLFontGL::getFontSansSerifSmall());
mOutfitWornText->setValue(value ? worn_string : "");
mOutfitNameText->setText(mOutfitName); // refresh LLTextViewModel to pick up font changes
+
+ static LLCachedControl<bool> use_color(gSavedSettings, "InventoryFavoritesColorText");
+ mOutfitNameText->setReadOnlyColor((mFavorite && use_color()) ? sDefaultFavoriteColor.get() : sDefaultTextColor.get());
}
void LLOutfitGalleryItem::setSelected(bool value)
@@ -1157,7 +1219,7 @@ void LLOutfitGalleryItem::setDefaultImage()
LLContextMenu* LLOutfitGalleryContextMenu::createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
LLUUID selected_id = mUUIDs.front();
@@ -1169,9 +1231,10 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu()
boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
registrar.add("Outfit.Edit", boost::bind(editOutfit));
registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
- registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id));
- registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2));
+ registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id));
+ registrar.add("Outfit.Favorite", boost::bind(&LLOutfitGalleryContextMenu::onFavorite, this, selected_id));
registrar.add("Outfit.Save", boost::bind(&LLOutfitGalleryContextMenu::onSave, this, selected_id));
enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2));
enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2));
@@ -1210,25 +1273,10 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility()
{
if (!mMenu) return;
bool have_selection = getSelectedOutfitID().notNull();
- mMenu->setItemVisible("expand", false);
- mMenu->setItemVisible("collapse", false);
mMenu->setItemVisible("thumbnail", have_selection);
- mMenu->setItemVisible("sepatator3", true);
- mMenu->setItemVisible("sort_folders_by_name", true);
LLOutfitListGearMenuBase::onUpdateItemsVisibility();
}
-void LLOutfitGalleryGearMenu::onChangeSortOrder()
-{
- bool sort_by_name = !gSavedSettings.getBOOL("OutfitGallerySortByName");
- gSavedSettings.setBOOL("OutfitGallerySortByName", sort_by_name);
- LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
- if (gallery)
- {
- gallery->reArrangeRows();
- }
-}
-
bool LLOutfitGalleryGearMenu::hasDefaultImage()
{
LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mOutfitList);
@@ -1345,6 +1393,15 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id)
}
}
+LLToggleableMenu* LLOutfitGallery::getSortMenu()
+{
+ if (!mSortMenu)
+ {
+ mSortMenu = new LLOutfitGallerySortMenu(this);
+ }
+ return mSortMenu->getMenu();
+}
+
LLUUID LLOutfitGallery::getPhotoAssetId(const LLUUID& outfit_id)
{
outfit_map_t::iterator outfit_it = mOutfitMap.find(outfit_id);
@@ -1360,3 +1417,84 @@ LLUUID LLOutfitGallery::getDefaultPhoto()
return LLUUID();
}
+
+//////////////////// LLOutfitGallerySortMenu ////////////////////
+
+LLOutfitGallerySortMenu::LLOutfitGallerySortMenu(LLOutfitListBase* parent_panel)
+ : mPanelHandle(parent_panel->getHandle())
+{
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ registrar.add("Sort.OnSort", { boost::bind(&LLOutfitGallerySortMenu::onSort, this, _2) });
+ enable_registrar.add("Sort.OnEnable", boost::bind(&LLOutfitGallerySortMenu::onEnable, this, _2));
+
+ mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
+ "menu_outfit_gallery_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ llassert(mMenu);
+}
+
+
+LLToggleableMenu* LLOutfitGallerySortMenu::getMenu()
+{
+ return mMenu;
+}
+
+void LLOutfitGallerySortMenu::updateItemsVisibility()
+{
+ onUpdateItemsVisibility();
+}
+
+void LLOutfitGallerySortMenu::onUpdateItemsVisibility()
+{
+ if (!mMenu) return;
+}
+
+bool LLOutfitGallerySortMenu::onEnable(LLSD::String param)
+{
+ static LLCachedControl<S32> sort_order(gSavedSettings, "OutfitGallerySortOrder", 0);
+ if ("favorites_to_top" == param)
+ {
+ return sort_order == 2;
+ }
+ else if ("images_to_top" == param)
+ {
+ return sort_order == 1;
+ }
+ else if ("by_name" == param)
+ {
+ return sort_order == 0;
+ }
+
+ return false;
+}
+
+void LLOutfitGallerySortMenu::onSort(LLSD::String param)
+{
+ S32 sort_order = gSavedSettings.getS32("OutfitGallerySortOrder");
+ S32 new_sort_order = 0;
+ if ("favorites_to_top" == param)
+ {
+ new_sort_order = 2;
+ }
+ else if ("images_to_top" == param)
+ {
+ new_sort_order = 1;
+ }
+ else if ("by_name" == param)
+ {
+ new_sort_order = 0;
+ }
+ if (sort_order == new_sort_order)
+ {
+ new_sort_order = sort_order ? 0 : 1;
+ }
+ gSavedSettings.setS32("OutfitGallerySortOrder", new_sort_order);
+
+ LLOutfitGallery* gallery = dynamic_cast<LLOutfitGallery*>(mPanelHandle.get());
+ if (gallery)
+ {
+ gallery->reArrangeRows();
+ }
+}
+
diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h
index fa441ff209..1487aa6f5e 100644
--- a/indra/newview/lloutfitgallery.h
+++ b/indra/newview/lloutfitgallery.h
@@ -42,11 +42,13 @@ class LLOutfitGalleryItem;
class LLOutfitListGearMenuBase;
class LLOutfitGalleryGearMenu;
class LLOutfitGalleryContextMenu;
+class LLOutfitGallerySortMenu;
class LLOutfitGallery : public LLOutfitListBase
{
public:
friend class LLOutfitGalleryGearMenu;
+ friend class LLOutfitGallerySortMenu;
friend class LLOutfitGalleryContextMenu;
friend class LLUpdateGalleryOnPhotoLinked;
@@ -102,10 +104,12 @@ public:
/*virtual*/ bool getHasExpandableFolders() { return false; }
+ /*virtual*/ void onChangeSortOrder(const LLSD& userdata) {};
void updateMessageVisibility();
bool hasDefaultImage(const LLUUID& outfit_cat_id);
void refreshOutfit(const LLUUID& category_id);
+ virtual LLToggleableMenu* getSortMenu();
protected:
/*virtual*/ void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id);
@@ -133,8 +137,9 @@ private:
void reArrangeRows(S32 row_diff = 0);
void updateRowsIfNeeded();
void updateGalleryWidth();
+ void handleInvFavColorChange();
- LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id);
+ LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id, bool is_favorite);
LLOutfitGalleryItem* getSelectedItem() const;
LLOutfitGalleryItem* getItem(const LLUUID& id) const;
@@ -176,6 +181,7 @@ private:
int mGalleryWidthFactor;
LLListContextMenu* mOutfitGalleryMenu;
+ LLOutfitGallerySortMenu* mSortMenu;
typedef std::map<LLUUID, LLOutfitGalleryItem*> outfit_map_t;
typedef outfit_map_t::value_type outfit_map_value_t;
@@ -187,6 +193,8 @@ private:
LLInventoryCategoriesObserver* mOutfitsObserver;
+
+ boost::signals2::connection mSavedSettingInvFavColor;
};
class LLOutfitGalleryContextMenu : public LLOutfitContextMenu
{
@@ -213,8 +221,6 @@ public:
protected:
/*virtual*/ void onUpdateItemsVisibility();
private:
- /*virtual*/ void onChangeSortOrder();
-
bool hasDefaultImage();
};
@@ -243,6 +249,7 @@ public:
bool setImageAssetId(LLUUID asset_id);
LLUUID getImageAssetId();
void setOutfitName(std::string name);
+ void setOutfitFavorite(bool is_favorite);
void setOutfitWorn(bool value);
void setSelected(bool value);
void setUUID(const LLUUID &outfit_id) {mUUID = outfit_id;}
@@ -250,6 +257,7 @@ public:
std::string getItemName() {return mOutfitName;}
bool isDefaultImage() {return mDefaultImage;}
+ bool isFavorite() { return mFavorite; }
bool isHidden() {return mHidden;}
void setHidden(bool hidden) {mHidden = hidden;}
@@ -268,7 +276,29 @@ private:
bool mDefaultImage;
bool mImageUpdatePending;
bool mHidden;
+ bool mFavorite;
std::string mOutfitName;
+
+ static bool sColorSetInitialized;
+ static LLUIColor sDefaultTextColor;
+ static LLUIColor sDefaultFavoriteColor;
+};
+
+class LLOutfitGallerySortMenu
+{
+public:
+ LLOutfitGallerySortMenu(LLOutfitListBase* parent_panel);
+
+ LLToggleableMenu* getMenu();
+ void updateItemsVisibility();
+
+private:
+ void onUpdateItemsVisibility();
+ bool onEnable(LLSD::String param);
+ void onSort(LLSD::String param);
+
+ LLToggleableMenu* mMenu;
+ LLHandle<LLPanel> mPanelHandle;
};
#endif // LL_LLOUTFITGALLERYCTRL_H
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 0f5f7aebf8..a7fda4b9d3 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -35,6 +35,7 @@
#include "llaccordionctrltab.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
+#include "llappviewer.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llinspecttexture.h"
@@ -45,6 +46,7 @@
#include "lloutfitobserver.h"
#include "lltoggleablemenu.h"
#include "lltransutil.h"
+#include "llviewercontrol.h"
#include "llviewermenu.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
@@ -53,14 +55,24 @@
static bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y);
static const LLOutfitTabNameComparator OUTFIT_TAB_NAME_COMPARATOR;
+static const LLOutfitTabFavComparator OUTFIT_TAB_FAV_COMPARATOR;
/*virtual*/
bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const
{
- std::string name1 = tab1->getTitle();
- std::string name2 = tab2->getTitle();
+ return (LLStringUtil::compareDict(tab1->getTitle(), tab2->getTitle()) < 0);
+}
+
+bool LLOutfitTabFavComparator::compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const
+{
+ LLOutfitAccordionCtrlTab* taba = (LLOutfitAccordionCtrlTab*)tab1;
+ LLOutfitAccordionCtrlTab* tabb = (LLOutfitAccordionCtrlTab*)tab2;
+ if (taba->getFavorite() != tabb->getFavorite())
+ {
+ return taba->getFavorite();
+ }
- return (LLStringUtil::compareDict(name1, name2) < 0);
+ return (LLStringUtil::compareDict(tab1->getTitle(), tab2->getTitle()) < 0);
}
struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLOutfitAccordionCtrlTab::Params>
@@ -80,6 +92,9 @@ const outfit_accordion_tab_params& get_accordion_tab_params()
{
initialized = true;
+ LLOutfitAccordionCtrlTab::sFavoriteIcon = LLUI::getUIImage("Inv_Favorite_Star_Full");
+ LLOutfitAccordionCtrlTab::sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", LLColor4U(255, 255, 255));
+
LLXMLNodePtr xmlNode;
if (LLUICtrlFactory::getLayeredXMLNode("outfit_accordion_tab.xml", xmlNode))
{
@@ -103,11 +118,20 @@ LLOutfitsList::LLOutfitsList()
, mAccordion(NULL)
, mListCommands(NULL)
, mItemSelected(false)
+ , mSortMenu(nullptr)
{
+ LLControlVariable* ctrl = gSavedSettings.getControl("InventoryFavoritesColorText");
+ if (ctrl)
+ {
+ mSavedSettingInvFavColor = ctrl->getSignal()->connect(boost::bind(&LLOutfitsList::handleInvFavColorChange, this));
+ }
}
LLOutfitsList::~LLOutfitsList()
{
+ delete mSortMenu;
+ mSavedSettingInvFavColor.disconnect();
+ mGearMenuConnection.disconnect();
}
bool LLOutfitsList::postBuild()
@@ -115,9 +139,25 @@ bool LLOutfitsList::postBuild()
mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
+ initComparator();
+
return LLOutfitListBase::postBuild();
}
+void LLOutfitsList::initComparator()
+{
+ S32 mode = gSavedSettings.getS32("OutfitListSortOrder");
+ if (mode == 0)
+ {
+ mAccordion->setComparator(&OUTFIT_TAB_NAME_COMPARATOR);
+ }
+ else
+ {
+ mAccordion->setComparator(&OUTFIT_TAB_FAV_COMPARATOR);
+ }
+ sortOutfits();
+}
+
//virtual
void LLOutfitsList::onOpen(const LLSD& info)
{
@@ -154,6 +194,7 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
tab->setName(name);
tab->setTitle(name);
+ tab->setFavorite(cat->getIsFavorite());
// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
tab->setDisplayChildren(false);
@@ -183,8 +224,9 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
// Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875)
tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id));
- // force showing list items that don't match current filter(EXT-7158)
- list->setForceShowingUnmatchedItems(true);
+ // Depending on settings, force showing list items that don't match current filter(EXT-7158)
+ static LLCachedControl<bool> list_filter(gSavedSettings, "OutfitListFilterFullList");
+ list->setForceShowingUnmatchedItems(list_filter(), false);
// Setting list commit callback to monitor currently selected wearable item.
list->setCommitCallback(boost::bind(&LLOutfitsList::onListSelectionChange, this, _1));
@@ -249,13 +291,11 @@ void LLOutfitsList::onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id)
{
if (mOutfitsMap[prev_id])
{
- mOutfitsMap[prev_id]->setTitleFontStyle("NORMAL");
- mOutfitsMap[prev_id]->setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor"));
+ ((LLOutfitAccordionCtrlTab*)mOutfitsMap[prev_id])->setOutfitSelected(false);
}
if (mOutfitsMap[base_id])
{
- mOutfitsMap[base_id]->setTitleFontStyle("BOLD");
- mOutfitsMap[base_id]->setTitleColor(LLUIColorTable::instance().getColor("SelectedOutfitTextColor"));
+ ((LLOutfitAccordionCtrlTab*)mOutfitsMap[base_id])->setOutfitSelected(true);
}
}
@@ -313,6 +353,11 @@ void LLOutfitsList::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid)
}
}
+void LLOutfitListBase::onAction(const LLSD& userdata)
+{
+ performAction(userdata.asString());
+}
+
// virtual
bool LLOutfitListBase::isActionEnabled(const LLSD& userdata)
{
@@ -425,11 +470,12 @@ void LLOutfitsList::updateChangedCategoryName(LLViewerInventoryCategory *cat, st
if (outfits_iter != mOutfitsMap.end())
{
// Update tab name with the new category name.
- LLAccordionCtrlTab* tab = outfits_iter->second;
+ LLOutfitAccordionCtrlTab* tab = (LLOutfitAccordionCtrlTab*) outfits_iter->second;
if (tab)
{
tab->setName(name);
tab->setTitle(name);
+ tab->setFavorite(cat->getIsFavorite());
}
}
}
@@ -521,7 +567,7 @@ void LLOutfitsList::onFilterSubStringChanged(const std::string& new_string, cons
LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
if (list)
{
- list->setFilterSubString(new_string, tab->getDisplayChildren());
+ list->setFilterSubString(new_string, true);
}
if (old_string.empty())
@@ -738,6 +784,75 @@ void LLOutfitsList::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUI
}
}
+void LLOutfitsList::handleInvFavColorChange()
+{
+ for (outfits_map_t::iterator iter = mOutfitsMap.begin();
+ iter != mOutfitsMap.end();
+ ++iter)
+ {
+ if (!iter->second) continue;
+ LLOutfitAccordionCtrlTab* tab = (LLOutfitAccordionCtrlTab*)iter->second;
+
+ // refresh font color
+ tab->setFavorite(tab->getFavorite());
+ }
+}
+
+void LLOutfitsList::onChangeSortOrder(const LLSD& userdata)
+{
+ std::string sort_data = userdata.asString();
+ if (sort_data == "favorites_to_top")
+ {
+ // at the moment this is a toggle
+ S32 val = gSavedSettings.getS32("OutfitListSortOrder");
+ gSavedSettings.setS32("OutfitListSortOrder", (val ? 0 : 1));
+
+ initComparator();
+ }
+ else if (sort_data == "show_entire_outfit")
+ {
+ bool new_val = !gSavedSettings.getBOOL("OutfitListFilterFullList");
+ gSavedSettings.setBOOL("OutfitListFilterFullList", new_val);
+
+ if (!getFilterSubString().empty())
+ {
+ for (outfits_map_t::value_type& outfit : mOutfitsMap)
+ {
+ LLAccordionCtrlTab* tab = outfit.second;
+ const LLUUID& category_id = outfit.first;
+ if (!tab) continue;
+
+ LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
+ if (list)
+ {
+ list->setForceRefresh(true);
+ list->setForceShowingUnmatchedItems(new_val, tab->getDisplayChildren());
+ }
+ applyFilterToTab(category_id, tab, getFilterSubString());
+ }
+ mAccordion->arrange();
+ }
+ }
+}
+
+LLToggleableMenu* LLOutfitsList::getSortMenu()
+{
+ if (!mSortMenu)
+ {
+ mSortMenu = new LLOutfitListSortMenu(this);
+ }
+ return mSortMenu->getMenu();
+}
+
+void LLOutfitsList::updateMenuItemsVisibility()
+{
+ if (mSortMenu)
+ {
+ mSortMenu->updateItemsVisibility();
+ }
+ LLOutfitListBase::updateMenuItemsVisibility();
+}
+
LLOutfitListGearMenuBase* LLOutfitsList::createGearMenu()
{
return new LLOutfitListGearMenu(this);
@@ -755,10 +870,10 @@ bool is_tab_header_clicked(LLAccordionCtrlTab* tab, S32 y)
LLOutfitListBase::LLOutfitListBase()
: LLPanelAppearanceTab()
, mIsInitialized(false)
+ , mGearMenu(nullptr)
{
mCategoriesObserver = new LLInventoryCategoriesObserver();
mOutfitMenu = new LLOutfitContextMenu(this);
- //mGearMenu = createGearMenu();
}
LLOutfitListBase::~LLOutfitListBase()
@@ -821,6 +936,10 @@ void LLOutfitListBase::observerCallback(const LLUUID& category_id)
void LLOutfitListBase::refreshList(const LLUUID& category_id)
{
+ if (LLAppViewer::instance()->quitRequested())
+ {
+ return;
+ }
bool wasNull = mRefreshListState.CategoryUUID.isNull();
mRefreshListState.CategoryUUID.setNull();
@@ -879,8 +998,18 @@ void LLOutfitListBase::onIdle(void* userdata)
void LLOutfitListBase::onIdleRefreshList()
{
+ if (LLAppViewer::instance()->quitRequested())
+ {
+ mRefreshListState.CategoryUUID.setNull();
+ gIdleCallbacks.deleteFunction(onIdle, this);
+ return;
+ }
if (mRefreshListState.CategoryUUID.isNull())
+ {
+ LL_WARNS() << "Called onIdleRefreshList without id" << LL_ENDL;
+ gIdleCallbacks.deleteFunction(onIdle, this);
return;
+ }
const F64 MAX_TIME = 0.05f;
F64 curent_time = LLTimer::getTotalSeconds();
@@ -924,8 +1053,8 @@ void LLOutfitListBase::onIdleRefreshList()
if (cat)
{
std::string name = cat->getName();
- updateChangedCategoryName(cat, name);
- }
+ updateChangedCategoryName(cat, name);
+ }
curent_time = LLTimer::getTotalSeconds();
if (curent_time >= end_time)
@@ -1022,12 +1151,6 @@ void LLOutfitListBase::ChangeOutfitSelection(LLWearableItemsList* list, const LL
bool LLOutfitListBase::postBuild()
{
- mGearMenu = createGearMenu();
-
- LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
-
- menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenuBase::updateItemsVisibility, mGearMenu));
- menu_gear_btn->setMenu(mGearMenu->getMenu());
return true;
}
@@ -1041,6 +1164,20 @@ void LLOutfitListBase::expandAllFolders()
onExpandAllFolders();
}
+void LLOutfitListBase::updateMenuItemsVisibility()
+{
+ mGearMenu->updateItemsVisibility();
+}
+
+LLToggleableMenu* LLOutfitListBase::getGearMenu()
+{
+ if (!mGearMenu)
+ {
+ mGearMenu = createGearMenu();
+ }
+ return mGearMenu->getMenu();
+};
+
void LLOutfitListBase::deselectOutfit(const LLUUID& category_id)
{
// Reset selection if the outfit is selected.
@@ -1053,7 +1190,7 @@ void LLOutfitListBase::deselectOutfit(const LLUUID& category_id)
LLContextMenu* LLOutfitContextMenu::createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
LLUUID selected_id = mUUIDs.front();
@@ -1064,9 +1201,10 @@ LLContextMenu* LLOutfitContextMenu::createMenu()
registrar.add("Outfit.TakeOff",
boost::bind(&LLAppearanceMgr::takeOffOutfit, &LLAppearanceMgr::instance(), selected_id));
registrar.add("Outfit.Edit", boost::bind(editOutfit));
- registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id));
- registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList));
+ registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitContextMenu::onThumbnail, this, selected_id));
+ registrar.add("Outfit.Favorite", boost::bind(&LLOutfitContextMenu::onFavorite, this, selected_id));
registrar.add("Outfit.Save", boost::bind(&LLOutfitContextMenu::onSave, this, selected_id));
enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2));
@@ -1117,6 +1255,16 @@ bool LLOutfitContextMenu::onVisible(LLSD::String param)
{
return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id);
}
+ else if ("favorites_add" == param)
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_cat_id);
+ return cat && !cat->getIsFavorite();
+ }
+ else if ("favorites_remove" == param)
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_cat_id);
+ return cat && cat->getIsFavorite();
+ }
return true;
}
@@ -1141,6 +1289,14 @@ void LLOutfitContextMenu::onThumbnail(const LLUUID &outfit_cat_id)
}
}
+void LLOutfitContextMenu::onFavorite(const LLUUID& outfit_cat_id)
+{
+ if (outfit_cat_id.notNull())
+ {
+ toggle_favorite(outfit_cat_id);
+ }
+}
+
void LLOutfitContextMenu::onSave(const LLUUID &outfit_cat_id)
{
if (outfit_cat_id.notNull())
@@ -1163,7 +1319,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)
{
llassert_always(mOutfitList);
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
registrar.add("Gear.Wear", boost::bind(&LLOutfitListGearMenuBase::onWear, this));
@@ -1171,14 +1327,13 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist)
registrar.add("Gear.Rename", boost::bind(&LLOutfitListGearMenuBase::onRename, this));
registrar.add("Gear.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList));
registrar.add("Gear.Create", boost::bind(&LLOutfitListGearMenuBase::onCreate, this, _2));
- registrar.add("Gear.Collapse", boost::bind(&LLOutfitListBase::onCollapseAllFolders, mOutfitList));
- registrar.add("Gear.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, mOutfitList));
registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this));
registrar.add("Gear.Save", boost::bind(&LLOutfitListGearMenuBase::onSave, this));
registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this));
- registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this));
+ registrar.add("Gear.Favorite", boost::bind(&LLOutfitListGearMenuBase::onFavorite, this));
+ registrar.add("Gear.SortByImage", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this));
enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2));
enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenuBase::onVisible, this, _2));
@@ -1312,6 +1467,16 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param)
{
return false;
}
+ else if ("favorites_add" == param)
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
+ return cat && !cat->getIsFavorite();
+ }
+ else if ("favorites_remove" == param)
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id);
+ return cat && cat->getIsFavorite();
+ }
return true;
}
@@ -1323,6 +1488,12 @@ void LLOutfitListGearMenuBase::onThumbnail()
LLFloaterReg::showInstance("change_item_thumbnail", data);
}
+void LLOutfitListGearMenuBase::onFavorite()
+{
+ const LLUUID& selected_outfit_id = getSelectedOutfitID();
+ toggle_favorite(selected_outfit_id);
+}
+
void LLOutfitListGearMenuBase::onChangeSortOrder()
{
@@ -1338,14 +1509,77 @@ LLOutfitListGearMenu::~LLOutfitListGearMenu()
void LLOutfitListGearMenu::onUpdateItemsVisibility()
{
if (!mMenu) return;
- mMenu->setItemVisible("expand", true);
- mMenu->setItemVisible("collapse", true);
mMenu->setItemVisible("thumbnail", getSelectedOutfitID().notNull());
- mMenu->setItemVisible("sepatator3", false);
- mMenu->setItemVisible("sort_folders_by_name", false);
+ mMenu->setItemVisible("favorite", getSelectedOutfitID().notNull());
LLOutfitListGearMenuBase::onUpdateItemsVisibility();
}
+//////////////////// LLOutfitListSortMenu ////////////////////
+
+LLOutfitListSortMenu::LLOutfitListSortMenu(LLOutfitListBase* parent_panel)
+ : mPanelHandle(parent_panel->getHandle())
+{
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ registrar.add("Sort.Collapse", { boost::bind(&LLOutfitListBase::onCollapseAllFolders, parent_panel) });
+ registrar.add("Sort.Expand", { boost::bind(&LLOutfitListBase::onExpandAllFolders, parent_panel) });
+ registrar.add("Sort.OnSort", { boost::bind(&LLOutfitListBase::onChangeSortOrder, parent_panel, _2) });
+ enable_registrar.add("Sort.OnEnable", boost::bind(&LLOutfitListSortMenu::onEnable, this, _2));
+
+ mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
+ "menu_outfit_list_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ llassert(mMenu);
+}
+
+
+LLToggleableMenu* LLOutfitListSortMenu::getMenu()
+{
+ return mMenu;
+}
+
+void LLOutfitListSortMenu::updateItemsVisibility()
+{
+ onUpdateItemsVisibility();
+}
+
+void LLOutfitListSortMenu::onUpdateItemsVisibility()
+{
+ if (!mMenu) return;
+ mMenu->setItemVisible("expand", true);
+ mMenu->setItemVisible("collapse", true);
+ mMenu->setItemVisible("sort_favorites_to_top", true);
+ mMenu->setItemVisible("show_entire_outfit_in_search", true);
+}
+
+bool LLOutfitListSortMenu::onEnable(LLSD::String param)
+{
+ if ("favorites_to_top" == param)
+ {
+ static LLCachedControl<S32> sort_order(gSavedSettings, "OutfitListSortOrder", 0);
+ return sort_order == 1;
+ }
+ else if ("show_entire_outfit" == param)
+ {
+ static LLCachedControl<bool> filter_mode(gSavedSettings, "OutfitListFilterFullList", 0);
+ return filter_mode;
+ }
+
+ return false;
+}
+
+
+//////////////////// LLOutfitAccordionCtrlTab ////////////////////
+
+LLUIImage* LLOutfitAccordionCtrlTab::sFavoriteIcon;
+LLUIColor LLOutfitAccordionCtrlTab::sFgColor;
+
+void LLOutfitAccordionCtrlTab::draw()
+{
+ LLAccordionCtrlTab::draw();
+ drawFavoriteIcon();
+}
+
bool LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
{
if (y >= getLocalRect().getHeight() - getHeaderHeight())
@@ -1366,4 +1600,61 @@ bool LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
return LLAccordionCtrlTab::handleToolTip(x, y, mask);
}
+
+void LLOutfitAccordionCtrlTab::setFavorite(bool is_favorite)
+{
+ mIsFavorite = is_favorite;
+ static LLUICachedControl<bool> highlight_color("InventoryFavoritesColorText", true);
+ if (!mIsSelected && mIsFavorite && highlight_color())
+ {
+ setTitleColor(LLUIColorTable::instance().getColor("InventoryFavoriteColor"));
+ }
+ else
+ {
+ setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor"));
+ }
+}
+
+void LLOutfitAccordionCtrlTab::setOutfitSelected(bool val)
+{
+ mIsSelected = val;
+ if (val)
+ {
+ setTitleFontStyle("BOLD");
+ setTitleColor(LLUIColorTable::instance().getColor("SelectedOutfitTextColor"));
+ }
+ else
+ {
+ setTitleFontStyle("NORMAL");
+ static LLUICachedControl<bool> highlight_color("InventoryFavoritesColorText", true);
+ if (mIsFavorite && highlight_color())
+ {
+ setTitleColor(LLUIColorTable::instance().getColor("InventoryFavoriteColor"));
+ }
+ else
+ {
+ setTitleColor(LLUIColorTable::instance().getColor("AccordionHeaderTextColor"));
+ }
+ }
+}
+
+void LLOutfitAccordionCtrlTab::drawFavoriteIcon()
+{
+ if (!mIsFavorite)
+ {
+ return;
+ }
+ static LLUICachedControl<bool> draw_star("InventoryFavoritesUseStar", true);
+ if (!draw_star)
+ {
+ return;
+ }
+
+ const S32 PAD = 2;
+ const S32 image_size = 18;
+
+ gl_draw_scaled_image(
+ getRect().getWidth() - image_size - PAD, getRect().getHeight() - image_size - PAD,
+ image_size, image_size, sFavoriteIcon->getImage(), sFgColor);
+}
// EOF
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index f581b419d9..8c926a85f6 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -41,6 +41,7 @@
class LLAccordionCtrlTab;
class LLInventoryCategoriesObserver;
class LLOutfitListGearMenuBase;
+class LLOutfitListSortMenuBase;
class LLWearableItemsList;
class LLListContextMenu;
@@ -61,6 +62,17 @@ public:
/*virtual*/ bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const;
};
+class LLOutfitTabFavComparator : public LLAccordionCtrl::LLTabComparator
+{
+ LOG_CLASS(LLOutfitTabFavComparator);
+
+public:
+ LLOutfitTabFavComparator() {};
+ virtual ~LLOutfitTabFavComparator() {};
+
+ /*virtual*/ bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const;
+};
+
class LLOutfitListBase : public LLPanelAppearanceTab
{
public:
@@ -92,6 +104,7 @@ public:
boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
void outfitRightClickCallBack(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id);
+ void onAction(const LLSD& userdata);
virtual bool isActionEnabled(const LLSD& userdata);
virtual void performAction(std::string action);
virtual bool hasItemSelected() = 0;
@@ -109,6 +122,12 @@ public:
virtual bool getHasExpandableFolders() = 0;
+ virtual void onChangeSortOrder(const LLSD& userdata) = 0;
+
+ virtual void updateMenuItemsVisibility();
+ virtual LLToggleableMenu* getGearMenu();
+ virtual bool getTrashMenuVisible() { return true; };
+
protected:
void observerCallback(const LLUUID& category_id);
virtual LLOutfitListGearMenuBase* createGearMenu() = 0;
@@ -139,6 +158,7 @@ protected:
selection_change_signal_t mSelectionChangeSignal;
LLListContextMenu* mOutfitMenu;
LLOutfitListGearMenuBase* mGearMenu;
+ boost::signals2::connection mGearMenuConnection;
};
//////////////////////////////////////////////////////////////////////////
@@ -155,7 +175,6 @@ protected:
/* virtual */ LLContextMenu* createMenu();
bool onEnable(LLSD::String param);
-
bool onVisible(LLSD::String param);
static void editOutfit();
@@ -163,6 +182,7 @@ protected:
static void renameOutfit(const LLUUID& outfit_cat_id);
void onThumbnail(const LLUUID &outfit_cat_id);
+ void onFavorite(const LLUUID& outfit_cat_id);
void onSave(const LLUUID &outfit_cat_id);
private:
@@ -182,6 +202,7 @@ public:
protected:
virtual void onUpdateItemsVisibility();
virtual void onThumbnail();
+ virtual void onFavorite();
virtual void onChangeSortOrder();
const LLUUID& getSelectedOutfitID();
@@ -202,6 +223,23 @@ private:
bool onVisible(LLSD::String param);
};
+class LLOutfitListSortMenu
+{
+public:
+ LLOutfitListSortMenu(LLOutfitListBase* parent_panel);
+
+ LLToggleableMenu* getMenu();
+ void updateItemsVisibility();
+
+private:
+ void onUpdateItemsVisibility();
+ bool onEnable(LLSD::String param);
+
+ LLToggleableMenu* mMenu;
+ LLHandle<LLPanel> mPanelHandle;
+};
+
+
class LLOutfitListGearMenu : public LLOutfitListGearMenuBase
{
public:
@@ -221,8 +259,16 @@ public:
Params() : cat_id("cat_id") {}
};
+ virtual void draw();
virtual bool handleToolTip(S32 x, S32 y, MASK mask);
+ void setFavorite(bool is_favorite);
+ bool getFavorite() const { return mIsFavorite; }
+ void setOutfitSelected(bool val);
+
+ static LLUIImage* sFavoriteIcon;
+ static LLUIColor sFgColor;
+
protected:
LLOutfitAccordionCtrlTab(const LLOutfitAccordionCtrlTab::Params &p)
: LLAccordionCtrlTab(p),
@@ -230,7 +276,11 @@ public:
{}
friend class LLUICtrlFactory;
+ void drawFavoriteIcon();
+
LLUUID mFolderID;
+ bool mIsFavorite = false;
+ bool mIsSelected = false;
};
/**
* @class LLOutfitsList
@@ -249,6 +299,7 @@ public:
virtual ~LLOutfitsList();
/*virtual*/ bool postBuild();
+ void initComparator();
/*virtual*/ void onOpen(const LLSD& info);
@@ -287,6 +338,10 @@ public:
/*virtual*/ bool getHasExpandableFolders() { return true; }
+ /*virtual*/ void onChangeSortOrder(const LLSD& userdata);
+ virtual LLToggleableMenu* getSortMenu();
+ void updateMenuItemsVisibility();
+
protected:
LLOutfitListGearMenuBase* createGearMenu();
@@ -357,6 +412,8 @@ private:
static void onOutfitRename(const LLSD& notification, const LLSD& response);
+ void handleInvFavColorChange();
+
//LLInventoryCategoriesObserver* mCategoriesObserver;
LLAccordionCtrl* mAccordion;
@@ -374,13 +431,15 @@ private:
// Used to monitor COF changes for updating items worn state. See EXT-8636.
uuid_vec_t mCOFLinkedItems;
- //LLOutfitListGearMenu* mGearMenu;
+ LLOutfitListSortMenu* mSortMenu;
//bool mIsInitialized;
/**
* True if there is a selection inside currently selected outfit
*/
bool mItemSelected;
+
+ boost::signals2::connection mSavedSettingInvFavColor;
};
#endif //LL_LLOUTFITSLIST_H
diff --git a/indra/newview/llpanelappearancetab.h b/indra/newview/llpanelappearancetab.h
index e4d16582de..e088c3e6f0 100644
--- a/indra/newview/llpanelappearancetab.h
+++ b/indra/newview/llpanelappearancetab.h
@@ -29,6 +29,8 @@
#include "llpanel.h"
+class LLToggleableMenu;
+
class LLPanelAppearanceTab : public LLPanel
{
public:
@@ -47,6 +49,11 @@ public:
const std::string& getFilterSubString() { return mFilterSubString; }
+ virtual void updateMenuItemsVisibility() = 0;
+ virtual LLToggleableMenu* getGearMenu() = 0;
+ virtual LLToggleableMenu* getSortMenu() = 0;
+ virtual bool getTrashMenuVisible() = 0;
+
protected:
/**
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index 7d55ba3265..01d4f426de 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -62,7 +62,7 @@ const std::string BLOCKED_PARAM_NAME = "blocked_to_select";
LLPanelBlockedList::LLPanelBlockedList()
: LLPanel()
{
- mCommitCallbackRegistrar.add("Block.Action", boost::bind(&LLPanelBlockedList::onCustomAction, this, _2));
+ mCommitCallbackRegistrar.add("Block.Action", { boost::bind(&LLPanelBlockedList::onCustomAction, this, _2), cb_info::UNTRUSTED_BLOCK });
mEnableCallbackRegistrar.add("Block.Check", boost::bind(&LLPanelBlockedList::isActionChecked, this, _2));
}
diff --git a/indra/newview/llpaneleditsky.cpp b/indra/newview/llpaneleditsky.cpp
index ea2b2ba944..b4a0f0570e 100644
--- a/indra/newview/llpaneleditsky.cpp
+++ b/indra/newview/llpaneleditsky.cpp
@@ -35,7 +35,6 @@
#include "llvirtualtrackball.h"
#include "llsettingssky.h"
#include "llenvironment.h"
-#include "llatmosphere.h"
#include "llviewercontrol.h"
namespace
@@ -926,13 +925,6 @@ void LLPanelSettingsSkyDensityTab::updateProfile()
mSkySettings->setAbsorptionConfigs(absorption_config);
mSkySettings->update();
setIsDirty();
-
- if (gAtmosphere)
- {
- AtmosphericModelSettings atmospheric_settings;
- LLEnvironment::getAtmosphericModelSettings(atmospheric_settings, mSkySettings);
- gAtmosphere->configureAtmosphericModel(atmospheric_settings);
- }
}
void LLPanelSettingsSkyDensityTab::onRayleighExponentialChanged()
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 282b6d4a0a..a90c17f56e 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -642,8 +642,8 @@ LLPanelEditWearable::LLPanelEditWearable()
, mWearablePtr(NULL)
, mWearableItem(NULL)
{
- mCommitCallbackRegistrar.add("ColorSwatch.Commit", boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1));
- mCommitCallbackRegistrar.add("TexturePicker.Commit", boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1));
+ mCommitCallbackRegistrar.add("ColorSwatch.Commit", { boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1) });
+ mCommitCallbackRegistrar.add("TexturePicker.Commit", { boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1) });
}
//virtual
diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp
index 9def7b8b03..2d659cd19d 100644
--- a/indra/newview/llpanelemojicomplete.cpp
+++ b/indra/newview/llpanelemojicomplete.cpp
@@ -68,9 +68,9 @@ LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p
{
LLScrollbar::Params sbparams;
sbparams.orientation(LLScrollbar::VERTICAL);
- sbparams.doc_size(mTotalEmojis);
+ sbparams.doc_size((S32)mTotalEmojis);
sbparams.doc_pos(0);
- sbparams.page_size(mVisibleEmojis);
+ sbparams.page_size((S32)mVisibleEmojis);
sbparams.change_callback([this](S32 index, LLScrollbar*) { onScrollbarChange(index); });
mScrollbar = LLUICtrlFactory::create<LLScrollbar>(sbparams);
addChild(mScrollbar);
@@ -283,8 +283,7 @@ void LLPanelEmojiComplete::onCommit()
{
if (mCurSelected < mTotalEmojis)
{
- LLSD value(wstring_to_utf8str(LLWString(1, mEmojis[mCurSelected].Character)));
- setValue(value);
+ setValue(ll_convert_to<std::string>(mEmojis[mCurSelected].Character));
LLUICtrl::onCommit();
}
}
@@ -441,7 +440,7 @@ void LLPanelEmojiComplete::updateConstraints()
{
mRenderRect = getLocalRect();
- mEmojiWidth = (U16)(mIconFont->getWidthF32(u8"\U0001F431") + mPadding * 2);
+ mEmojiWidth = (U16)(mIconFont->getWidthF32(LLWString(1, 0x1F431).c_str()) + mPadding * 2);
if (mVertical)
{
mEmojiHeight = mIconFont->getLineHeight() + mPadding * 2;
diff --git a/indra/newview/llpanelenvironment.cpp b/indra/newview/llpanelenvironment.cpp
index be61c44b7c..d3df88b65e 100644
--- a/indra/newview/llpanelenvironment.cpp
+++ b/indra/newview/llpanelenvironment.cpp
@@ -48,6 +48,7 @@
#include "llappviewer.h"
#include "llcallbacklist.h"
+#include "llviewercontrol.h"
#include "llviewerparcelmgr.h"
#include "llinventorymodel.h"
@@ -939,19 +940,29 @@ void LLPanelEnvironmentInfo::udpateApparentTimeOfDay()
S32Hours hourofday(secondofday);
S32Seconds secondofhour(secondofday - hourofday);
S32Minutes minutesofhour(secondofhour);
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
bool am_pm(hourofday.value() >= 12);
- if (hourofday.value() < 1)
- hourofday = S32Hours(12);
- if (hourofday.value() > 12)
- hourofday -= S32Hours(12);
+ if (!use_24h)
+ {
+ if (hourofday.value() < 1)
+ hourofday = S32Hours(12);
+ if (hourofday.value() > 12)
+ hourofday -= S32Hours(12);
+ }
std::string lblminute(((minutesofhour.value() < 10) ? "0" : "") + LLSD(minutesofhour.value()).asString());
-
mLabelApparentTime->setTextArg("[HH]", LLSD(hourofday.value()).asString());
mLabelApparentTime->setTextArg("[MM]", lblminute);
- mLabelApparentTime->setTextArg("[AP]", std::string(am_pm ? "PM" : "AM"));
+ if (use_24h)
+ {
+ mLabelApparentTime->setTextArg("[AP]", std::string());
+ }
+ else
+ {
+ mLabelApparentTime->setTextArg("[AP]", std::string(am_pm ? "PM" : "AM"));
+ }
mLabelApparentTime->setTextArg("[PRC]", LLSD((S32)(100 * perc)).asString());
}
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index b07946dd5d..5de68950c6 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -470,7 +470,7 @@ LLPanelFace::LLPanelFace()
mNeedMediaTitle(true)
{
USE_TEXTURE = LLTrans::getString("use_texture");
- mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2));
+ mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", { boost::bind(&LLPanelFace::menuDoToSelected, this, _2) });
mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2));
}
@@ -481,10 +481,6 @@ LLPanelFace::~LLPanelFace()
void LLPanelFace::onVisibilityChange(bool new_visibility)
{
- if (new_visibility)
- {
- gAgent.showLatestFeatureNotification("gltf");
- }
LLPanel::onVisibilityChange(new_visibility);
}
diff --git a/indra/newview/llpanelgroupbulk.cpp b/indra/newview/llpanelgroupbulk.cpp
index 433db74cda..8032e207cd 100644
--- a/indra/newview/llpanelgroupbulk.cpp
+++ b/indra/newview/llpanelgroupbulk.cpp
@@ -56,6 +56,7 @@ LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) :
mGroupID(group_id),
mBulkAgentList(NULL),
mOKButton(NULL),
+ mAddButton(nullptr),
mRemoveButton(NULL),
mGroupName(NULL),
mLoadingText(),
@@ -79,29 +80,18 @@ LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl()
}
}
-// static
-void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata)
+void LLPanelGroupBulkImpl::callbackClickAdd(LLPanelGroupBulk* panelp)
{
- if (LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)userdata)
- {
- // Right now this is hard coded with some knowledge that it is part
- // of a floater since the avatar picker needs to be added as a dependent
- // floater to the parent floater.
- // Soon the avatar picker will be embedded into this panel
- // instead of being it's own separate floater. But that is next week.
- // This will do for now. -jwolk May 10, 2006
- LLView* button = panelp->findChild<LLButton>("add_button");
- LLFloater* root_floater = gFloaterView->getParentFloater(panelp);
- LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(
- [&](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&)
- {
- panelp->mImplementation->addUsers(agent_ids);
- }, true, false, false, root_floater->getName(), button);
- if (picker)
+ LLFloater* root_floater = gFloaterView->getParentFloater(panelp);
+ LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(
+ [this](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&)
{
- root_floater->addDependentFloater(picker);
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(panelp->mImplementation->mGroupID);
- }
+ addUsers(agent_ids);
+ }, true, false, false, root_floater->getName(), mAddButton);
+ if (picker)
+ {
+ root_floater->addDependentFloater(picker);
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
}
}
diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp
index 3c764887a6..1d3edad0f3 100644
--- a/indra/newview/llpanelgroupbulkban.cpp
+++ b/indra/newview/llpanelgroupbulkban.cpp
@@ -68,35 +68,26 @@ bool LLPanelGroupBulkBan::postBuild()
mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation);
}
- LLButton* button = getChild<LLButton>("add_button", recurse);
- if ( button )
+ mImplementation->mAddButton = getChild<LLButton>("add_button", recurse);
+ // default to opening avatarpicker automatically
+ mImplementation->mAddButton->setClickedCallback(
+ [this](LLUICtrl* ctrl, const LLSD& param)
{
- // default to opening avatarpicker automatically
- // (*impl::callbackClickAdd)((void*)this);
- button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this);
- }
+ mImplementation->callbackClickAdd(this);
+ });
mImplementation->mRemoveButton =
getChild<LLButton>("remove_button", recurse);
- if ( mImplementation->mRemoveButton )
- {
- mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation);
- mImplementation->mRemoveButton->setEnabled(false);
- }
+ mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation);
+ mImplementation->mRemoveButton->setEnabled(false);
mImplementation->mOKButton =
getChild<LLButton>("ban_button", recurse);
- if ( mImplementation->mOKButton )
- {
- mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this);
- mImplementation->mOKButton->setEnabled(false);
- }
+ mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this);
+ mImplementation->mOKButton->setEnabled(false);
- button = getChild<LLButton>("cancel_button", recurse);
- if ( button )
- {
- button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation);
- }
+ LLButton* button = getChild<LLButton>("cancel_button", recurse);
+ button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation);
mImplementation->mTooManySelected = getString("ban_selection_too_large");
mImplementation->mBanNotPermitted = getString("ban_not_permitted");
diff --git a/indra/newview/llpanelgroupbulkimpl.h b/indra/newview/llpanelgroupbulkimpl.h
index 5a479f8117..5515bd6d9a 100644
--- a/indra/newview/llpanelgroupbulkimpl.h
+++ b/indra/newview/llpanelgroupbulkimpl.h
@@ -44,7 +44,7 @@ public:
LLPanelGroupBulkImpl(const LLUUID& group_id);
~LLPanelGroupBulkImpl();
- static void callbackClickAdd(void* userdata);
+ void callbackClickAdd(LLPanelGroupBulk* panelp);
static void callbackClickRemove(void* userdata);
static void callbackClickCancel(void* userdata);
@@ -70,6 +70,7 @@ public:
LLNameListCtrl* mBulkAgentList;
LLButton* mOKButton;
+ LLButton* mAddButton;
LLButton* mRemoveButton;
LLTextBox* mGroupName;
diff --git a/indra/newview/llpanelgroupcreate.cpp b/indra/newview/llpanelgroupcreate.cpp
index 4a370525ff..bc7b5caddf 100644
--- a/indra/newview/llpanelgroupcreate.cpp
+++ b/indra/newview/llpanelgroupcreate.cpp
@@ -85,6 +85,7 @@ bool LLPanelGroupCreate::postBuild()
mInsignia = getChild<LLTextureCtrl>("insignia", true);
mInsignia->setAllowLocalTexture(false);
+ mInsignia->setBakeTextureEnabled(false);
mInsignia->setCanApplyImmediately(false);
return true;
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index ca429ae2f8..270ca29403 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -197,6 +197,7 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group)
{
mInsignia->setCommitCallback(onCommitAny, this);
mInsignia->setAllowLocalTexture(false);
+ mInsignia->setBakeTextureEnabled(false);
}
mFounderName = getChild<LLTextBox>("founder_name");
diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp
index 41373cd7f5..7596c0eba8 100644
--- a/indra/newview/llpanellandmarkinfo.cpp
+++ b/indra/newview/llpanellandmarkinfo.cpp
@@ -41,6 +41,7 @@
#include "lllandmarkactions.h"
#include "llparcel.h"
#include "llslurl.h"
+#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
@@ -326,7 +327,8 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem)
}
else
{
- std::string timeStr = getString("acquired_date");
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ std::string timeStr = use_24h ? getString("acquired_date") : getString("acquired_date_ampm");
LLSD substitution;
substitution["datetime"] = (S32) time_utc;
LLStringUtil::format (timeStr, substitution);
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index fb7ccbfe4c..5a0cd1a823 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -458,10 +458,10 @@ void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list
// List Commands Handlers
void LLLandmarksPanel::initListCommandsHandlers()
{
- mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", boost::bind(&LLLandmarksPanel::onAddAction, this, _2));
- mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2));
- mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", boost::bind(&LLLandmarksPanel::onCustomAction, this, _2));
- mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2));
+ mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", { boost::bind(&LLLandmarksPanel::onAddAction, this, _2) });
+ mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", { boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2) });
+ mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", { boost::bind(&LLLandmarksPanel::onCustomAction, this, _2) });
+ mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", { boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2)} );
mEnableCallbackRegistrar.add("Places.LandmarksGear.Check", boost::bind(&LLLandmarksPanel::isActionChecked, this, _2));
mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));
mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index ed80c8b732..cae11a942c 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -81,15 +81,16 @@ bool LLPanelLogin::sCredentialSet = false;
LLPointer<LLCredential> load_user_credentials(std::string &user_key)
{
- if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid()))
+ std::string grid{ LLGridManager::instance().getGrid() };
+ if (gSecAPIHandler->hasCredentialMap("login_list", grid))
{
// user_key should be of "name Resident" format
- return gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key);
+ return gSecAPIHandler->loadFromCredentialMap("login_list", grid, user_key);
}
else
{
// legacy (or legacy^2, since it also tries to load from settings)
- return gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ return gSecAPIHandler->loadCredential(grid);
}
}
@@ -223,7 +224,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
sendChildToBack(getChildView("forgot_password_text"));
sendChildToBack(getChildView("sign_up_text"));
- std::string current_grid = LLGridManager::getInstance()->getGrid();
+ LLGridManager& gridmgr{ LLGridManager::instance() };
+ std::string current_grid = gridmgr.getGrid();
if (!mFirstLoginThisInstall)
{
LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo");
@@ -237,7 +239,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
// Load all of the grids, sorted, and then add a bar and the current grid at the top
server_choice_combo->removeall();
- std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ std::map<std::string, std::string> known_grids = gridmgr.getKnownGrids();
for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
grid_choice != known_grids.end();
grid_choice++)
@@ -251,7 +253,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
server_choice_combo->sortByName();
LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL;
- server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
+ server_choice_combo->add(gridmgr.getGridLabel(),
current_grid,
ADD_TOP);
server_choice_combo->selectFirstItem();
@@ -760,6 +762,7 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl)
LL_DEBUGS("AppInit")<<new_start_slurl.asString()<<LL_ENDL;
LLComboBox* location_combo = sInstance->getChild<LLComboBox>("start_location_combo");
+ LLGridManager& gridmgr{ LLGridManager::instance() };
/*
* Determine whether or not the new_start_slurl modifies the grid.
*
@@ -774,17 +777,17 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl)
{
case LLSLURL::LOCATION:
{
- std::string slurl_grid = LLGridManager::getInstance()->getGrid(new_start_slurl.getGrid());
+ std::string slurl_grid = gridmgr.getGrid(new_start_slurl.getGrid());
if ( ! slurl_grid.empty() ) // is that a valid grid?
{
- if ( slurl_grid != LLGridManager::getInstance()->getGrid() ) // new grid?
+ if ( slurl_grid != gridmgr.getGrid() ) // new grid?
{
// the slurl changes the grid, so update everything to match
- LLGridManager::getInstance()->setGridChoice(slurl_grid);
+ gridmgr.setGridChoice(slurl_grid);
// update the grid selector to match the slurl
LLComboBox* server_combo = sInstance->getChild<LLComboBox>("server_combo");
- std::string server_label(LLGridManager::getInstance()->getGridLabel(slurl_grid));
+ std::string server_label(gridmgr.getGridLabel(slurl_grid));
server_combo->setSimple(server_label);
updateServer(); // to change the links and splash screen
@@ -831,8 +834,7 @@ void LLPanelLogin::autologinToLocation(const LLSLURL& slurl)
if ( LLPanelLogin::sInstance != NULL )
{
- void* unused_parameter = 0;
- LLPanelLogin::sInstance->onClickConnect(unused_parameter);
+ LLPanelLogin::sInstance->onClickConnect(false);
}
}
@@ -872,7 +874,8 @@ void LLPanelLogin::loadLoginPage()
{
if (!sInstance) return;
- LLURI login_page = LLURI(LLGridManager::getInstance()->getLoginPage());
+ LLGridManager& gridmgr{ LLGridManager::instance() };
+ LLURI login_page = LLURI(gridmgr.getLoginPage());
LLSD params(login_page.queryMap());
LL_DEBUGS("AppInit") << "login_page: " << login_page << LL_ENDL;
@@ -899,7 +902,7 @@ void LLPanelLogin::loadLoginPage()
params["channel"] = LLVersionInfo::instance().getChannel();
// Grid
- params["grid"] = LLGridManager::getInstance()->getGridId();
+ params["grid"] = gridmgr.getGridId();
// add OS info
params["os"] = LLOSInfo::instance().getOSStringSimple();
@@ -916,7 +919,7 @@ void LLPanelLogin::loadLoginPage()
login_page.path(),
params));
- gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
+ gViewerWindow->setMenuBackgroundColor(false, !gridmgr.isInProductionGrid());
LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
if (web_browser->getCurrentNavUrl() != login_uri.asString())
@@ -949,9 +952,10 @@ void LLPanelLogin::onClickConnect(bool commit_fields)
// the grid definitions may come from a user-supplied grids.xml, so they may not be good
LL_DEBUGS("AppInit")<<"grid "<<combo_val.asString()<<LL_ENDL;
+ LLGridManager& gridmgr{ LLGridManager::instance() };
try
{
- LLGridManager::getInstance()->setGridChoice(combo_val.asString());
+ gridmgr.setGridChoice(combo_val.asString());
}
catch (LLInvalidGridName ex)
{
@@ -984,7 +988,7 @@ void LLPanelLogin::onClickConnect(bool commit_fields)
std::string identifier_type;
cred->identifierType(identifier_type);
LLSD allowed_credential_types;
- LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types);
+ gridmgr.getLoginIdentifierTypes(allowed_credential_types);
// check the typed in credential type against the credential types expected by the server.
for(LLSD::array_iterator i = allowed_credential_types.beginArray();
@@ -1133,6 +1137,7 @@ void LLPanelLogin::updateServer()
{
if (sInstance)
{
+ LLGridManager& gridmgr{ LLGridManager::instance() };
try
{
// if they've selected another grid, we should load the credentials
@@ -1152,7 +1157,7 @@ void LLPanelLogin::updateServer()
// populate dropbox and setFields
// Note: following call is related to initializeLoginInfo()
- LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(gridmgr.getGrid());
sInstance->populateUserList(credential);
// restore creds
@@ -1165,12 +1170,12 @@ void LLPanelLogin::updateServer()
{
// populate dropbox and setFields
// Note: following call is related to initializeLoginInfo()
- LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(gridmgr.getGrid());
sInstance->populateUserList(credential);
}
// update the login panel links
- bool system_grid = LLGridManager::getInstance()->isSystemGrid();
+ bool system_grid = gridmgr.isSystemGrid();
// Want to vanish not only create_new_account_btn, but also the
// title text over it, so turn on/off the whole layout_panel element.
@@ -1219,11 +1224,12 @@ void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential)
getChild<LLUICtrl>("password_edit")->setValue(std::string());
mUsernameLength = 0;
mPasswordLength = 0;
+ std::string grid{ LLGridManager::instance().getGrid() };
- if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid()))
+ if (gSecAPIHandler->hasCredentialMap("login_list", grid))
{
LLSecAPIHandler::credential_map_t credencials;
- gSecAPIHandler->loadCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), credencials);
+ gSecAPIHandler->loadCredentialMap("login_list", grid, credencials);
LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin();
LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end();
@@ -1278,7 +1284,8 @@ void LLPanelLogin::onSelectServer()
LLComboBox* server_combo = getChild<LLComboBox>("server_combo");
LLSD server_combo_val = server_combo->getSelectedValue();
LL_INFOS("AppInit") << "grid "<<server_combo_val.asString()<< LL_ENDL;
- LLGridManager::getInstance()->setGridChoice(server_combo_val.asString());
+ auto& gridmgr{ LLGridManager::instance() };
+ gridmgr.setGridChoice(server_combo_val.asString());
addFavoritesToStartLocation();
/*
@@ -1308,7 +1315,7 @@ void LLPanelLogin::onSelectServer()
LLSLURL slurl(location); // generata a slurl from the location combo contents
if (location.empty()
|| (slurl.getType() == LLSLURL::LOCATION
- && slurl.getGrid() != LLGridManager::getInstance()->getGrid())
+ && slurl.getGrid() != gridmgr.getGrid())
)
{
// the grid specified by the location is not this one, so clear the combo
@@ -1338,7 +1345,7 @@ bool LLPanelLogin::getShowFavorites()
}
// static
-std::string LLPanelLogin::getUserName(LLPointer<LLCredential> &cred)
+std::string LLPanelLogin::getUserName(const LLPointer<LLCredential> &cred)
{
if (cred.isNull())
{
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index a1bf25fb05..ce708e7a0e 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -85,7 +85,7 @@ public:
static bool getShowFavorites();
// extract name from cred in a format apropriate for username field
- static std::string getUserName(LLPointer<LLCredential> &cred);
+ static std::string getUserName(const LLPointer<LLCredential> &cred);
private:
friend class LLPanelLoginListener;
diff --git a/indra/newview/llpanelloginlistener.cpp b/indra/newview/llpanelloginlistener.cpp
index fb6f034b7f..aeaf2d1d00 100644
--- a/indra/newview/llpanelloginlistener.cpp
+++ b/indra/newview/llpanelloginlistener.cpp
@@ -32,9 +32,19 @@
#include "llpanelloginlistener.h"
// STL headers
// std headers
+#include <iomanip>
+#include <memory>
// external library headers
// other Linden headers
+#include "llcombobox.h"
#include "llpanellogin.h"
+#include "llsdutil.h"
+#include "llsecapi.h"
+#include "llslurl.h"
+#include "llstartup.h"
+#include "lluictrl.h"
+#include "llviewernetwork.h"
+#include "stringize.h"
LLPanelLoginListener::LLPanelLoginListener(LLPanelLogin* instance):
LLEventAPI("LLPanelLogin", "Access to LLPanelLogin methods"),
@@ -43,9 +53,195 @@ LLPanelLoginListener::LLPanelLoginListener(LLPanelLogin* instance):
add("onClickConnect",
"Pretend user clicked the \"Log In\" button",
&LLPanelLoginListener::onClickConnect);
+ add("login",
+ "Login to Second Life with saved credentials.\n"
+ "Pass [\"username\"] to select credentials previously saved with that username.\n"
+ "Pass [\"slurl\"] to specify target location.\n"
+ "Pass [\"grid\"] to select one of the valid grids in grids.xml.",
+ &LLPanelLoginListener::login,
+ llsd::map("reply", LLSD::String()));
+ add("savedLogins",
+ "Return \"logins\" as a list of {} saved login names.\n"
+ "Pass [\"grid\"] to select one of the valid grids in grids.xml.",
+ &LLPanelLoginListener::savedLogins,
+ llsd::map("reply", LLSD::String()));
}
void LLPanelLoginListener::onClickConnect(const LLSD&) const
{
mPanel->onClickConnect(false);
}
+
+namespace
+{
+
+ std::string gridkey(const std::string& grid)
+ {
+ if (grid.find('.') != std::string::npos)
+ {
+ return grid;
+ }
+ else
+ {
+ return stringize("util.", grid, ".lindenlab.com");
+ }
+ }
+
+} // anonymous namespace
+
+void LLPanelLoginListener::login(const LLSD& args) const
+{
+ // Although we require a "reply" key, don't instantiate a Response object:
+ // if things go well, response to our invoker will come later, once the
+ // viewer gets the response from the login server.
+ std::string username(args["username"]), slurlstr(args["slurl"]), grid(args["grid"]);
+ LL_DEBUGS("AppInit") << "Login with saved credentials";
+ if (! username.empty())
+ {
+ LL_CONT << " for user " << std::quoted(username);
+ }
+ if (! slurlstr.empty())
+ {
+ LL_CONT << " to location " << std::quoted(slurlstr);
+ }
+ if (! grid.empty())
+ {
+ LL_CONT << " on grid " << std::quoted(grid);
+ }
+ LL_CONT << LL_ENDL;
+
+ // change grid first, allowing slurl to override
+ auto& gridmgr{ LLGridManager::instance() };
+ if (! grid.empty())
+ {
+ grid = gridkey(grid);
+ // setGridChoice() can throw LLInvalidGridName -- but if so, let it
+ // propagate, trusting that LLEventAPI will catch it and send an
+ // appropriate reply.
+ auto server_combo = mPanel->getChild<LLComboBox>("server_combo");
+ server_combo->setSimple(gridmgr.getGridLabel(grid));
+ LLPanelLogin::updateServer();
+ }
+ if (! slurlstr.empty())
+ {
+ LLSLURL slurl(slurlstr);
+ if (! slurl.isSpatial())
+ {
+ // don't bother with LLTHROW() because we expect LLEventAPI to
+ // catch and report back to invoker
+ throw DispatchError(stringize("Invalid start SLURL ", std::quoted(slurlstr)));
+ }
+ // Bypass LLStartUp::setStartSLURL() because, after validating as
+ // above, it bounces right back to LLPanelLogin::onUpdateStartSLURL().
+ // It also sets the "NextLoginLocation" user setting, but as with grid,
+ // we don't yet know whether that's desirable for scripted login.
+ LLPanelLogin::onUpdateStartSLURL(slurl);
+ }
+ if (! username.empty())
+ {
+ // Transform (e.g.) "Nat Linden" to the internal form expected by
+ // loadFromCredentialMap(), e.g. "nat_linden"
+ LLStringUtil::toLower(username);
+ LLStringUtil::replaceChar(username, ' ', '_');
+ LLStringUtil::replaceChar(username, '.', '_');
+
+ // call gridmgr.getGrid() because our caller didn't necessarily pass
+ // ["grid"] -- or it might have been overridden by the SLURL
+ auto cred = gSecAPIHandler->loadFromCredentialMap("login_list",
+ gridmgr.getGrid(),
+ username);
+ LLPanelLogin::setFields(cred);
+ }
+
+ if (mPanel->getChild<LLUICtrl>("username_combo")->getValue().asString().empty() ||
+ mPanel->getChild<LLUICtrl>("password_edit") ->getValue().asString().empty())
+ {
+ // as above, let LLEventAPI report back to invoker
+ throw DispatchError(stringize("Unrecognized username ", std::quoted(username)));
+ }
+
+ // Here we're about to trigger actual login, which is all we can do in
+ // this method. All subsequent responses must come via the "login"
+ // LLEventPump.
+ LLEventPumps::instance().obtain("login").listen(
+ "Lua login",
+ [args]
+ (const LLBoundListener& conn, const LLSD& update)
+ {
+ LLSD response{ llsd::map("ok", false) };
+ if (update["change"] == "connect")
+ {
+ // success!
+ response["ok"] = true;
+ }
+ else if (update["change"] == "disconnect")
+ {
+ // Does this ever actually happen?
+ // LLLoginInstance::handleDisconnect() says it's a placeholder.
+ response["error"] = "login disconnect";
+ }
+ else if (update["change"] == "fail.login")
+ {
+ // why?
+ // LLLoginInstance::handleLoginFailure() has special code to
+ // handle "tos", "update" and "mfa_challenge". Do not respond
+ // automatically because these things are SUPPOSED to engage
+ // the user.
+ // Copy specific response fields because there's an enormous
+ // chunk of stuff that comes back on success.
+ LLSD data{ update["data"] };
+ const char* fields[] = {
+ "reason",
+ "error_code"
+ };
+ for (auto field : fields)
+ {
+ response[field] = data[field];
+ }
+ response["error"] = update["message"];
+ }
+ else
+ {
+ // Ignore all other "change" values: LLLogin sends multiple update
+ // events. Only a few of them (above) indicate completion.
+ return;
+ }
+ // For all the completion cases, disconnect from the "login"
+ // LLEventPump.
+ conn.disconnect();
+ // and at last, send response to the original invoker
+ sendReply(response, args);
+ });
+
+ // Turn the Login crank.
+ mPanel->onClickConnect(false);
+}
+
+LLSD LLPanelLoginListener::savedLogins(const LLSD& args) const
+{
+ LL_INFOS() << "called with " << args << LL_ENDL;
+ std::string grid = (args.has("grid")? gridkey(args["grid"].asString())
+ : LLGridManager::instance().getGrid());
+ if (! gSecAPIHandler->hasCredentialMap("login_list", grid))
+ {
+ LL_INFOS() << "no creds for " << grid << LL_ENDL;
+ return llsd::map("error",
+ stringize("No saved logins for grid ", std::quoted(grid)));
+ }
+ LLSecAPIHandler::credential_map_t creds;
+ gSecAPIHandler->loadCredentialMap("login_list", grid, creds);
+ auto result = llsd::map(
+ "logins",
+ llsd::toArray(
+ creds,
+ [](const auto& pair)
+ {
+ return llsd::map(
+ "name",
+ LLPanelLogin::getUserName(pair.second),
+ "key",
+ pair.first);
+ }));
+ LL_INFOS() << "returning creds " << result << LL_ENDL;
+ return result;
+}
diff --git a/indra/newview/llpanelloginlistener.h b/indra/newview/llpanelloginlistener.h
index b552ccd5b0..f2f4d70ff9 100644
--- a/indra/newview/llpanelloginlistener.h
+++ b/indra/newview/llpanelloginlistener.h
@@ -40,6 +40,8 @@ public:
private:
void onClickConnect(const LLSD&) const;
+ void login(const LLSD&) const;
+ LLSD savedLogins(const LLSD&) const;
LLPanelLogin* mPanel;
};
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 377af4384a..36a8069010 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -68,6 +68,7 @@ const std::string FILTERS_FILENAME("filters.xml");
const std::string ALL_ITEMS("All Items");
const std::string RECENT_ITEMS("Recent Items");
const std::string WORN_ITEMS("Worn Items");
+const std::string FAVORITES("Favorites");
static LLPanelInjector<LLPanelMainInventory> t_inventory("panel_main_inventory");
@@ -78,9 +79,9 @@ static LLPanelInjector<LLPanelMainInventory> t_inventory("panel_main_inventory")
class LLFloaterInventoryFinder : public LLFloater
{
public:
- LLFloaterInventoryFinder( LLPanelMainInventory* inventory_view);
- virtual void draw();
- /*virtual*/ bool postBuild();
+ LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view);
+ void draw();
+ bool postBuild();
void changeFilter(LLInventoryFilter* filter);
void updateElementsFromFilter();
bool getCheckShowEmpty();
@@ -90,17 +91,35 @@ public:
void onCreatorSelfFilterCommit();
void onCreatorOtherFilterCommit();
- static void onTimeAgo(LLUICtrl*, void *);
- static void onCloseBtn(void* user_data);
- static void selectAllTypes(void* user_data);
- static void selectNoTypes(void* user_data);
+ void onTimeAgo();
+ void onCloseBtn();
+ void selectAllTypes();
+ void selectNoTypes();
private:
- LLPanelMainInventory* mPanelMainInventory;
- LLSpinCtrl* mSpinSinceDays;
- LLSpinCtrl* mSpinSinceHours;
- LLCheckBoxCtrl* mCreatorSelf;
- LLCheckBoxCtrl* mCreatorOthers;
- LLInventoryFilter* mFilter;
+ LLPanelMainInventory* mPanelMainInventory{ nullptr };
+ LLSpinCtrl* mSpinSinceDays{ nullptr };
+ LLSpinCtrl* mSpinSinceHours{ nullptr };
+ LLCheckBoxCtrl* mCreatorSelf{ nullptr };
+ LLCheckBoxCtrl* mCreatorOthers{ nullptr };
+ LLInventoryFilter* mFilter{ nullptr };
+
+ LLCheckBoxCtrl* mCheckAnimation{ nullptr };
+ LLCheckBoxCtrl* mCheckCallingCard{ nullptr };
+ LLCheckBoxCtrl* mCheckClothing{ nullptr };
+ LLCheckBoxCtrl* mCheckGesture{ nullptr };
+ LLCheckBoxCtrl* mCheckLandmark{ nullptr };
+ LLCheckBoxCtrl* mCheckMaterial{ nullptr };
+ LLCheckBoxCtrl* mCheckNotecard{ nullptr };
+ LLCheckBoxCtrl* mCheckObject{ nullptr };
+ LLCheckBoxCtrl* mCheckScript{ nullptr };
+ LLCheckBoxCtrl* mCheckSounds{ nullptr };
+ LLCheckBoxCtrl* mCheckTexture{ nullptr };
+ LLCheckBoxCtrl* mCheckSnapshot{ nullptr };
+ LLCheckBoxCtrl* mCheckSettings{ nullptr };
+ LLCheckBoxCtrl* mCheckShowEmpty{ nullptr };
+ LLCheckBoxCtrl* mCheckSinceLogoff{ nullptr };
+
+ LLRadioGroup* mRadioDateSearchDirection{ nullptr };
};
///----------------------------------------------------------------------------
@@ -125,14 +144,16 @@ LLPanelMainInventory::LLPanelMainInventory(const LLPanel::Params& p)
mGalleryRootUpdatedConnection()
{
// Menu Callbacks (non contex menus)
- mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2));
- mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLPanelMainInventory::closeAllFolders, this));
- mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
- mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
- mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLPanelMainInventory::doCreate, this, _2));
- mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this));
- mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this));
- mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2));
+ mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLPanelMainInventory::doToSelected, this, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", { boost::bind(&LLPanelMainInventory::closeAllFolders, this) });
+ mCommitCallbackRegistrar.add("Inventory.EmptyTrash", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory,
+ "ConfirmEmptyTrash", LLFolderType::FT_TRASH), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory,
+ "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.DoCreate", { boost::bind(&LLPanelMainInventory::doCreate, this, _2) });
+ mCommitCallbackRegistrar.add("Inventory.ShowFilters", { boost::bind(&LLPanelMainInventory::toggleFindOptions, this) });
+ mCommitCallbackRegistrar.add("Inventory.ResetFilters", { boost::bind(&LLPanelMainInventory::resetFilters, this) });
+ mCommitCallbackRegistrar.add("Inventory.SetSortBy", { boost::bind(&LLPanelMainInventory::setSortBy, this, _2) });
mEnableCallbackRegistrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl *, const LLSD &) { return LLPanelMainInventory::hasSettingsInventory(); });
mEnableCallbackRegistrar.add("Inventory.MaterialsEnabled", [](LLUICtrl *, const LLSD &) { return LLPanelMainInventory::hasMaterialsInventory(); });
@@ -196,6 +217,17 @@ bool LLPanelMainInventory::postBuild()
worn_filter.markDefault();
mWornItemsPanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mWornItemsPanel, _1, _2));
}
+
+ LLInventoryPanel* favorites_panel = getChild<LLInventoryPanel>(FAVORITES);
+ if (favorites_panel)
+ {
+ favorites_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER));
+ LLInventoryFilter& favorites_filter = favorites_panel->getFilter();
+ favorites_filter.setEmptyLookupMessage("InventoryNoMatchingFavorites");
+ favorites_filter.markDefault();
+ favorites_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, favorites_panel, _1, _2));
+ }
+
mSearchTypeCombo = getChild<LLComboBox>("search_type");
if(mSearchTypeCombo)
{
@@ -734,7 +766,6 @@ bool LLPanelMainInventory::filtersVisible(void* user_data)
void LLPanelMainInventory::onClearSearch()
{
bool initially_active = false;
- LLFloater *finder = getFinder();
if (mActivePanel && (getActivePanel() != mWornItemsPanel))
{
initially_active = mActivePanel->getFilter().isNotDefault();
@@ -743,9 +774,9 @@ void LLPanelMainInventory::onClearSearch()
mActivePanel->setFilterLinks(LLInventoryFilter::FILTERLINK_INCLUDE_LINKS);
}
- if (finder)
+ if (LLFloaterInventoryFinder* finder = getFinder())
{
- LLFloaterInventoryFinder::selectAllTypes(finder);
+ finder->selectAllTypes();
}
// re-open folders that were initially open in case filter was active
@@ -1145,36 +1176,53 @@ bool LLFloaterInventoryFinder::postBuild()
const LLRect& viewrect = mPanelMainInventory->getRect();
setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight()));
- childSetAction("All", selectAllTypes, this);
- childSetAction("None", selectNoTypes, this);
+ childSetAction("All", [this](LLUICtrl*, const LLSD&) { selectAllTypes(); });
+ childSetAction("None", [this](LLUICtrl*, const LLSD&) { selectNoTypes(); });
mSpinSinceHours = getChild<LLSpinCtrl>("spin_hours_ago");
- childSetCommitCallback("spin_hours_ago", onTimeAgo, this);
+ mSpinSinceHours->setCommitCallback([this](LLUICtrl*, const LLSD&) { onTimeAgo(); });
mSpinSinceDays = getChild<LLSpinCtrl>("spin_days_ago");
- childSetCommitCallback("spin_days_ago", onTimeAgo, this);
+ mSpinSinceDays->setCommitCallback([this](LLUICtrl*, const LLSD&) { onTimeAgo(); });
mCreatorSelf = getChild<LLCheckBoxCtrl>("check_created_by_me");
mCreatorOthers = getChild<LLCheckBoxCtrl>("check_created_by_others");
mCreatorSelf->setCommitCallback(boost::bind(&LLFloaterInventoryFinder::onCreatorSelfFilterCommit, this));
mCreatorOthers->setCommitCallback(boost::bind(&LLFloaterInventoryFinder::onCreatorOtherFilterCommit, this));
- childSetAction("Close", onCloseBtn, this);
+ mCheckAnimation = getChild<LLCheckBoxCtrl>("check_animation");
+ mCheckCallingCard = getChild<LLCheckBoxCtrl>("check_calling_card");
+ mCheckClothing = getChild<LLCheckBoxCtrl>("check_clothing");
+ mCheckGesture = getChild<LLCheckBoxCtrl>("check_gesture");
+ mCheckLandmark = getChild<LLCheckBoxCtrl>("check_landmark");
+ mCheckMaterial = getChild<LLCheckBoxCtrl>("check_material");
+ mCheckNotecard = getChild<LLCheckBoxCtrl>("check_notecard");
+ mCheckObject = getChild<LLCheckBoxCtrl>("check_object");
+ mCheckScript = getChild<LLCheckBoxCtrl>("check_script");
+ mCheckSounds = getChild<LLCheckBoxCtrl>("check_sound");
+ mCheckTexture = getChild<LLCheckBoxCtrl>("check_texture");
+ mCheckSnapshot = getChild<LLCheckBoxCtrl>("check_snapshot");
+ mCheckSettings = getChild<LLCheckBoxCtrl>("check_settings");
+ mCheckShowEmpty = getChild<LLCheckBoxCtrl>("check_show_empty");
+ mCheckSinceLogoff = getChild<LLCheckBoxCtrl>("check_since_logoff");
+
+ mRadioDateSearchDirection = getChild<LLRadioGroup>("date_search_direction");
+
+ childSetAction("Close", [this](LLUICtrl*, const LLSD&) { onCloseBtn(); });
updateElementsFromFilter();
+
return true;
}
-void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data)
-{
- LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data;
- if (!self) return;
- if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() )
+void LLFloaterInventoryFinder::onTimeAgo()
+{
+ if (mSpinSinceDays->get() || mSpinSinceHours->get())
{
- self->getChild<LLUICtrl>("check_since_logoff")->setValue(false);
+ mCheckSinceLogoff->setValue(false);
- U32 days = (U32)self->mSpinSinceDays->get();
- U32 hours = (U32)self->mSpinSinceHours->get();
+ U32 days = (U32)mSpinSinceDays->get();
+ U32 hours = (U32)mSpinSinceHours->get();
if (hours >= 24)
{
// Try to handle both cases of spinner clicking and text input in a sensible fashion as best as possible.
@@ -1190,11 +1238,11 @@ void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data)
days = hours / 24;
}
hours = (U32)hours % 24;
- self->mSpinSinceHours->setFocus(false);
- self->mSpinSinceDays->setFocus(false);
- self->mSpinSinceDays->set((F32)days);
- self->mSpinSinceHours->set((F32)hours);
- self->mSpinSinceHours->setFocus(true);
+ mSpinSinceHours->setFocus(false);
+ mSpinSinceDays->setFocus(false);
+ mSpinSinceDays->set((F32)days);
+ mSpinSinceHours->set((F32)hours);
+ mSpinSinceHours->setFocus(true);
}
}
}
@@ -1223,29 +1271,28 @@ void LLFloaterInventoryFinder::updateElementsFromFilter()
// update the ui elements
setTitle(mFilter->getName());
- getChild<LLUICtrl>("check_animation")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION));
-
- getChild<LLUICtrl>("check_calling_card")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD));
- getChild<LLUICtrl>("check_clothing")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE));
- getChild<LLUICtrl>("check_gesture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE));
- getChild<LLUICtrl>("check_landmark")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK));
- getChild<LLUICtrl>("check_material")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MATERIAL));
- getChild<LLUICtrl>("check_notecard")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD));
- getChild<LLUICtrl>("check_object")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT));
- getChild<LLUICtrl>("check_script")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL));
- getChild<LLUICtrl>("check_sound")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND));
- getChild<LLUICtrl>("check_texture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE));
- getChild<LLUICtrl>("check_snapshot")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT));
- getChild<LLUICtrl>("check_settings")->setValue((S32)(filter_types & 0x1 << LLInventoryType::IT_SETTINGS));
- getChild<LLUICtrl>("check_show_empty")->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS);
-
- getChild<LLUICtrl>("check_created_by_me")->setValue(show_created_by_me);
- getChild<LLUICtrl>("check_created_by_others")->setValue(show_created_by_others);
-
- getChild<LLUICtrl>("check_since_logoff")->setValue(mFilter->isSinceLogoff());
+ mCheckAnimation->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION));
+ mCheckCallingCard->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD));
+ mCheckClothing->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE));
+ mCheckGesture->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE));
+ mCheckLandmark->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK));
+ mCheckMaterial->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MATERIAL));
+ mCheckNotecard->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD));
+ mCheckObject->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT));
+ mCheckScript->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL));
+ mCheckSounds->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND));
+ mCheckTexture->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE));
+ mCheckSnapshot->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT));
+ mCheckSettings->setValue((S32)(filter_types & 0x1 << LLInventoryType::IT_SETTINGS));
+ mCheckShowEmpty->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS);
+
+ mCreatorSelf->setValue(show_created_by_me);
+ mCreatorOthers->setValue(show_created_by_others);
+
+ mCheckSinceLogoff->setValue(mFilter->isSinceLogoff());
mSpinSinceHours->set((F32)(hours % 24));
mSpinSinceDays->set((F32)(hours / 24));
- getChild<LLRadioGroup>("date_search_direction")->setSelectedIndex(date_search_direction);
+ mRadioDateSearchDirection->setSelectedIndex(date_search_direction);
}
void LLFloaterInventoryFinder::draw()
@@ -1253,80 +1300,80 @@ void LLFloaterInventoryFinder::draw()
U64 filter = 0xffffffffffffffffULL;
bool filtered_by_all_types = true;
- if (!getChild<LLUICtrl>("check_animation")->getValue())
+ if (!mCheckAnimation->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_ANIMATION);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_calling_card")->getValue())
+ if (!mCheckCallingCard->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_clothing")->getValue())
+ if (!mCheckClothing->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_WEARABLE);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_gesture")->getValue())
+ if (!mCheckGesture->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_GESTURE);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_landmark")->getValue())
+ if (!mCheckLandmark->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_LANDMARK);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_material")->getValue())
+ if (!mCheckMaterial->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_MATERIAL);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_notecard")->getValue())
+ if (!mCheckNotecard->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_NOTECARD);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_object")->getValue())
+ if (!mCheckObject->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_OBJECT);
filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_script")->getValue())
+ if (!mCheckScript->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_LSL);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_sound")->getValue())
+ if (!mCheckSounds->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_SOUND);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_texture")->getValue())
+ if (!mCheckTexture->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_TEXTURE);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_snapshot")->getValue())
+ if (!mCheckSnapshot->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT);
filtered_by_all_types = false;
}
- if (!getChild<LLUICtrl>("check_settings")->getValue())
+ if (!mCheckSettings->getValue())
{
filter &= ~(0x1 << LLInventoryType::IT_SETTINGS);
filtered_by_all_types = false;
@@ -1444,65 +1491,56 @@ void LLFloaterInventoryFinder::onCreatorOtherFilterCommit()
bool LLFloaterInventoryFinder::getCheckShowEmpty()
{
- return getChild<LLUICtrl>("check_show_empty")->getValue();
+ return mCheckShowEmpty->getValue();
}
bool LLFloaterInventoryFinder::getCheckSinceLogoff()
{
- return getChild<LLUICtrl>("check_since_logoff")->getValue();
+ return mCheckSinceLogoff->getValue();
}
U32 LLFloaterInventoryFinder::getDateSearchDirection()
{
- return getChild<LLRadioGroup>("date_search_direction")->getSelectedIndex();
+ return mRadioDateSearchDirection->getSelectedIndex();
}
-void LLFloaterInventoryFinder::onCloseBtn(void* user_data)
+void LLFloaterInventoryFinder::onCloseBtn()
{
- LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data;
- finderp->closeFloater();
+ closeFloater();
}
-// static
-void LLFloaterInventoryFinder::selectAllTypes(void* user_data)
-{
- LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data;
- if(!self) return;
-
- self->getChild<LLUICtrl>("check_animation")->setValue(true);
- self->getChild<LLUICtrl>("check_calling_card")->setValue(true);
- self->getChild<LLUICtrl>("check_clothing")->setValue(true);
- self->getChild<LLUICtrl>("check_gesture")->setValue(true);
- self->getChild<LLUICtrl>("check_landmark")->setValue(true);
- self->getChild<LLUICtrl>("check_material")->setValue(true);
- self->getChild<LLUICtrl>("check_notecard")->setValue(true);
- self->getChild<LLUICtrl>("check_object")->setValue(true);
- self->getChild<LLUICtrl>("check_script")->setValue(true);
- self->getChild<LLUICtrl>("check_sound")->setValue(true);
- self->getChild<LLUICtrl>("check_texture")->setValue(true);
- self->getChild<LLUICtrl>("check_snapshot")->setValue(true);
- self->getChild<LLUICtrl>("check_settings")->setValue(true);
+void LLFloaterInventoryFinder::selectAllTypes()
+{
+ mCheckAnimation->setValue(true);
+ mCheckCallingCard->setValue(true);
+ mCheckClothing->setValue(true);
+ mCheckGesture->setValue(true);
+ mCheckLandmark->setValue(true);
+ mCheckMaterial->setValue(true);
+ mCheckNotecard->setValue(true);
+ mCheckObject->setValue(true);
+ mCheckScript->setValue(true);
+ mCheckSounds->setValue(true);
+ mCheckTexture->setValue(true);
+ mCheckSnapshot->setValue(true);
+ mCheckSettings->setValue(true);
}
-//static
-void LLFloaterInventoryFinder::selectNoTypes(void* user_data)
-{
- LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data;
- if(!self) return;
-
- self->getChild<LLUICtrl>("check_animation")->setValue(false);
- self->getChild<LLUICtrl>("check_calling_card")->setValue(false);
- self->getChild<LLUICtrl>("check_clothing")->setValue(false);
- self->getChild<LLUICtrl>("check_gesture")->setValue(false);
- self->getChild<LLUICtrl>("check_landmark")->setValue(false);
- self->getChild<LLUICtrl>("check_material")->setValue(false);
- self->getChild<LLUICtrl>("check_notecard")->setValue(false);
- self->getChild<LLUICtrl>("check_object")->setValue(false);
- self->getChild<LLUICtrl>("check_script")->setValue(false);
- self->getChild<LLUICtrl>("check_sound")->setValue(false);
- self->getChild<LLUICtrl>("check_texture")->setValue(false);
- self->getChild<LLUICtrl>("check_snapshot")->setValue(false);
- self->getChild<LLUICtrl>("check_settings")->setValue(false);
+void LLFloaterInventoryFinder::selectNoTypes()
+{
+ mCheckAnimation->setValue(false);
+ mCheckCallingCard->setValue(false);
+ mCheckClothing->setValue(false);
+ mCheckGesture->setValue(false);
+ mCheckLandmark->setValue(false);
+ mCheckMaterial->setValue(false);
+ mCheckNotecard->setValue(false);
+ mCheckObject->setValue(false);
+ mCheckScript->setValue(false);
+ mCheckSounds->setValue(false);
+ mCheckTexture->setValue(false);
+ mCheckSnapshot->setValue(false);
+ mCheckSettings->setValue(false);
}
//////////////////////////////////////////////////////////////////////////////////
@@ -1516,7 +1554,7 @@ void LLPanelMainInventory::initListCommandsHandlers()
mBackBtn->setCommitCallback(boost::bind(&LLPanelMainInventory::onBackFolderClicked, this));
mForwardBtn->setCommitCallback(boost::bind(&LLPanelMainInventory::onForwardFolderClicked, this));
- mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2));
+ mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", { boost::bind(&LLPanelMainInventory::onCustomAction, this, _2), cb_info::UNTRUSTED_BLOCK });
mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2));
mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2));
mEnableCallbackRegistrar.add("Inventory.GearDefault.Visible", boost::bind(&LLPanelMainInventory::isActionVisible, this, _2));
diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp
index 6e4e9f426d..7041f7945d 100644
--- a/indra/newview/llpanelmediasettingssecurity.cpp
+++ b/indra/newview/llpanelmediasettingssecurity.cpp
@@ -49,8 +49,8 @@
LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() :
mParent( NULL )
{
- mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this));
- mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this));
+ mCommitCallbackRegistrar.add("Media.whitelistAdd", { boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Media.whitelistDelete", { boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this), cb_info::UNTRUSTED_BLOCK });
// build dialog from XML
buildFromFile( "panel_media_settings_security.xml");
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index 2dd4866da3..86a88d6793 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -89,24 +89,24 @@ LLPanelNearByMedia::LLPanelNearByMedia()
gSavedSettings.getControl("ParcelMediaAutoPlayEnable")->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2));
- mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", boost::bind(&LLPanelNearByMedia::onClickEnableAll, this));
- mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", boost::bind(&LLPanelNearByMedia::onClickDisableAll, this));
- mCommitCallbackRegistrar.add("MediaListCtrl.GoMediaPrefs", boost::bind(&LLPanelNearByMedia::onAdvancedButtonClick, this));
- mCommitCallbackRegistrar.add("MediaListCtrl.MoreLess", boost::bind(&LLPanelNearByMedia::onMoreLess, this));
- mCommitCallbackRegistrar.add("SelectedMediaCtrl.Stop", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaStop, this));
- mCommitCallbackRegistrar.add("SelectedMediaCtrl.Play", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPlay, this));
- mCommitCallbackRegistrar.add("SelectedMediaCtrl.Pause", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPause, this));
- mCommitCallbackRegistrar.add("SelectedMediaCtrl.Mute", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaMute, this));
- mCommitCallbackRegistrar.add("SelectedMediaCtrl.Volume", boost::bind(&LLPanelNearByMedia::onCommitSelectedMediaVolume, this));
- mCommitCallbackRegistrar.add("SelectedMediaCtrl.Zoom", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaZoom, this));
- mCommitCallbackRegistrar.add("SelectedMediaCtrl.Unzoom", boost::bind(&LLPanelNearByMedia::onClickSelectedMediaUnzoom, this));
+ mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", { boost::bind(&LLPanelNearByMedia::onClickEnableAll, this) });
+ mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", { boost::bind(&LLPanelNearByMedia::onClickDisableAll, this) });
+ mCommitCallbackRegistrar.add("MediaListCtrl.GoMediaPrefs", { boost::bind(&LLPanelNearByMedia::onAdvancedButtonClick, this) });
+ mCommitCallbackRegistrar.add("MediaListCtrl.MoreLess", { boost::bind(&LLPanelNearByMedia::onMoreLess, this) });
+ mCommitCallbackRegistrar.add("SelectedMediaCtrl.Stop", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaStop, this) });
+ mCommitCallbackRegistrar.add("SelectedMediaCtrl.Play", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPlay, this) });
+ mCommitCallbackRegistrar.add("SelectedMediaCtrl.Pause", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaPause, this) });
+ mCommitCallbackRegistrar.add("SelectedMediaCtrl.Mute", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaMute, this) });
+ mCommitCallbackRegistrar.add("SelectedMediaCtrl.Volume", { boost::bind(&LLPanelNearByMedia::onCommitSelectedMediaVolume, this) });
+ mCommitCallbackRegistrar.add("SelectedMediaCtrl.Zoom", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaZoom, this) });
+ mCommitCallbackRegistrar.add("SelectedMediaCtrl.Unzoom", { boost::bind(&LLPanelNearByMedia::onClickSelectedMediaUnzoom, this) });
// Context menu handler.
mCommitCallbackRegistrar.add("SelectedMediaCtrl.Action",
- [this](LLUICtrl* ctrl, const LLSD& data)
+ {[this](LLUICtrl* ctrl, const LLSD& data)
{
onMenuAction(data);
- });
+ }});
mEnableCallbackRegistrar.add("SelectedMediaCtrl.Visible",
[this](LLUICtrl* ctrl, const LLSD& data)
{
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 0a3a2e753a..76eb2fd017 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -296,7 +296,7 @@ LLPanelObject::LLPanelObject()
mHasClipboardRot(false),
mSizeChanged(false)
{
- mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2));
+ mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", { boost::bind(&LLPanelObject::menuDoToSelected, this, _2) });
mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2));
}
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index ef7986603b..9a5b7a5d15 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -129,6 +129,7 @@ public:
virtual void navigateToFolder(bool new_window = false, bool change_mode = false) {}
virtual bool isItemRenameable() const;
virtual bool renameItem(const std::string& new_name);
+ virtual bool isFavorite() const { return false; }
virtual bool isItemMovable() const;
virtual bool isItemRemovable(bool check_worn = true) const;
virtual bool removeItem();
@@ -306,17 +307,28 @@ bool LLTaskInvFVBridge::isItemRenameable() const
bool LLTaskInvFVBridge::renameItem(const std::string& new_name)
{
- if (LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()))
+ LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
+ if (!object)
{
- if (LLViewerInventoryItem* item = (LLViewerInventoryItem*)object->getInventoryObject(mUUID))
- {
- if (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE, GOD_LIKE))
- {
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->rename(new_name);
- object->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, false);
- }
- }
+ return false;
+ }
+ if (!object->permModify())
+ {
+ LLNotificationsUtil::add("CantModifyContentInNoModTask");
+ return false;
+ }
+
+ LLViewerInventoryItem* item = NULL;
+ item = (LLViewerInventoryItem*)object->getInventoryObject(mUUID);
+ if (item && (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(),
+ GP_OBJECT_MANIPULATE, GOD_LIKE)))
+ {
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
+ new_item->rename(new_name);
+ object->updateInventory(
+ new_item,
+ TASK_INVENTORY_ITEM_KEY,
+ false);
}
return true;
@@ -1332,14 +1344,16 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par
mShowRootFolder(p.show_root_folder)
{
// Setup context menu callbacks
- mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2));
- mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
- mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
- mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&do_nothing));
- mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&do_nothing));
- mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&do_nothing));
- mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this));
- mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&do_nothing));
+ mCommitCallbackRegistrar.add("Inventory.DoToSelected", { boost::bind(&LLPanelObjectInventory::doToSelected, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.EmptyTrash",
+ { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound",
+ { boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.DoCreate", { boost::bind(&do_nothing) });
+ mCommitCallbackRegistrar.add("Inventory.AttachObject", { boost::bind(&do_nothing) });
+ mCommitCallbackRegistrar.add("Inventory.BeginIMSession", { boost::bind(&do_nothing) });
+ mCommitCallbackRegistrar.add("Inventory.Share", { boost::bind(&LLAvatarActions::shareWithAvatars, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", { boost::bind(&do_nothing) });
}
// Destroys the object
@@ -1364,7 +1378,23 @@ bool LLPanelObjectInventory::postBuild()
void LLPanelObjectInventory::doToSelected(const LLSD& userdata)
{
- LLInventoryAction::doToSelected(&gInventory, mFolders, userdata.asString());
+ std::string action = userdata.asString();
+ if ("rename" == action || "delete" == action)
+ {
+ LLViewerObject* objectp = gObjectList.findObject(mTaskUUID);
+ if (objectp && !objectp->permModify())
+ {
+ LLNotificationsUtil::add("CantModifyContentInNoModTask");
+ }
+ else
+ {
+ LLInventoryAction::doToSelected(&gInventory, mFolders, action);
+ }
+ }
+ else
+ {
+ LLInventoryAction::doToSelected(&gInventory, mFolders, action);
+ }
}
void LLPanelObjectInventory::clearContents()
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 4cd4afaa5a..241cb97f06 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -157,7 +157,7 @@ public:
{
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
- registrar.add("Wearable.Create", boost::bind(onCreate, _2));
+ registrar.add("Wearable.Create", { boost::bind(onCreate, _2), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
llassert(LLMenuGL::sMenuContainer != NULL);
LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
@@ -226,7 +226,7 @@ public:
LLHandle<LLView> flat_list_handle = flat_list->getHandle();
LLHandle<LLPanel> inventory_panel_handle = inventory_panel->getHandle();
- registrar.add("AddWearable.Gear.Sort", boost::bind(onSort, flat_list_handle, inventory_panel_handle, _2));
+ registrar.add("AddWearable.Gear.Sort", { boost::bind(onSort, flat_list_handle, inventory_panel_handle, _2) });
enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2));
enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2));
@@ -404,7 +404,9 @@ LLPanelOutfitEdit::LLPanelOutfitEdit()
mWearableListManager(NULL),
mPlusBtn(NULL),
mWearablesGearMenuBtn(NULL),
- mGearMenuBtn(NULL)
+ mGearMenuBtn(NULL),
+ mStatus(NULL),
+ mCurrentOutfitName(NULL)
{
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(false);
@@ -1307,7 +1309,7 @@ void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type
showWearablesListView();
//e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE
- applyListViewFilter(static_cast<EListViewItemType>(LVIT_SHAPE + type));
+ applyListViewFilter(EListViewItemType(LVIT_SHAPE + EListViewItemType(type)));
mWearableItemsList->setMenuWearableType(type);
}
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index 47c02793a3..e2e2cf1a61 100644
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -33,6 +33,7 @@
#include "llfloatersidepanelcontainer.h"
#include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h"
+#include "llmenubutton.h"
#include "llnotificationsutil.h"
#include "lloutfitgallery.h"
#include "lloutfitobserver.h"
@@ -53,12 +54,17 @@ static const std::string SAVE_BTN("save_btn");
static LLPanelInjector<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory");
-LLPanelOutfitsInventory::LLPanelOutfitsInventory() :
- mMyOutfitsPanel(NULL),
- mCurrentOutfitPanel(NULL),
- mActivePanel(NULL),
- mAppearanceTabs(NULL),
- mInitialized(false)
+LLPanelOutfitsInventory::LLPanelOutfitsInventory()
+ : mMyOutfitsPanel(nullptr)
+ , mCurrentOutfitPanel(nullptr)
+ , mActivePanel(nullptr)
+ , mAppearanceTabs(nullptr)
+ , mInitialized(false)
+ , mGearMenu(nullptr)
+ , mSortMenu(nullptr)
+ , mTrashBtn(nullptr)
+ , mSortMenuPanel(nullptr)
+ , mTrashMenuPanel(nullptr)
{
gAgentWearables.addLoadedCallback(boost::bind(&LLPanelOutfitsInventory::onWearablesLoaded, this));
gAgentWearables.addLoadingStartedCallback(boost::bind(&LLPanelOutfitsInventory::onWearablesLoading, this));
@@ -75,6 +81,9 @@ LLPanelOutfitsInventory::~LLPanelOutfitsInventory()
{
gSavedSettings.setS32("LastAppearanceTab", mAppearanceTabs->getCurrentPanelIndex());
}
+ mGearMenuConnection.disconnect();
+ mSortMenuConnection.disconnect();
+ mTrashMenuConnection.disconnect();
}
// virtual
@@ -258,6 +267,22 @@ void LLPanelOutfitsInventory::initListCommandsHandlers()
mOutfitGalleryPanel->childSetAction("trash_btn", boost::bind(&LLPanelOutfitsInventory::onTrashButtonClick, this));
}
+void LLPanelOutfitsInventory::setMenuButtons(LLMenuButton* gear_menu, LLMenuButton* sort_menu, LLButton* trash_btn, LLPanel* sort_menu_panel, LLPanel* trash_menu_panel)
+{
+ mGearMenu = gear_menu;
+ mSortMenu = sort_menu;
+ mTrashBtn = trash_btn;
+ mSortMenuPanel = sort_menu_panel;
+ mTrashMenuPanel = trash_menu_panel;
+
+ mGearMenuConnection.disconnect();
+ mSortMenuConnection.disconnect();
+ mTrashMenuConnection.disconnect();
+ mGearMenuConnection = mGearMenu->setMouseDownCallback(boost::bind(&LLPanelOutfitsInventory::onGearMouseDown, this));
+ mSortMenuConnection = mSortMenu->setMouseDownCallback(boost::bind(&LLPanelOutfitsInventory::onGearMouseDown, this));
+ mTrashMenuConnection = mTrashBtn->setClickedCallback(boost::bind(&LLPanelOutfitsInventory::onTrashButtonClick, this));
+}
+
void LLPanelOutfitsInventory::updateListCommands()
{
bool trash_enabled = isActionEnabled("delete");
@@ -284,6 +309,14 @@ void LLPanelOutfitsInventory::onTrashButtonClick()
}
}
+void LLPanelOutfitsInventory::onGearMouseDown()
+{
+ if (mActivePanel)
+ {
+ mActivePanel->updateMenuItemsVisibility();
+ }
+}
+
bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
{
return mActivePanel && mActivePanel->isActionEnabled(userdata);
@@ -320,6 +353,28 @@ void LLPanelOutfitsInventory::onTabChange()
mActivePanel->checkFilterSubString();
mActivePanel->onOpen(LLSD());
+ if (mGearMenu)
+ {
+ mGearMenu->setMenu(mActivePanel->getGearMenu(), LLMenuButton::MP_BOTTOM_LEFT);
+ }
+ if (mSortMenu && mSortMenuPanel)
+ {
+ LLToggleableMenu* menu = mActivePanel->getSortMenu();
+ if (menu)
+ {
+ mSortMenu->setMenu(menu, LLMenuButton::MP_BOTTOM_LEFT);
+ mSortMenuPanel->setVisible(true);
+ }
+ else
+ {
+ mSortMenuPanel->setVisible(false);
+ }
+ }
+ if (mTrashMenuPanel)
+ {
+ mTrashMenuPanel->setVisible(mActivePanel->getTrashMenuVisible());
+ }
+
updateVerbs();
}
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index e046681e95..29f7eb44f7 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -30,11 +30,13 @@
#include "llpanel.h"
+class LLButton;
class LLOutfitGallery;
class LLOutfitsList;
class LLOutfitListGearMenuBase;
class LLPanelAppearanceTab;
class LLPanelWearing;
+class LLMenuButton;
class LLMenuGL;
class LLSidepanelAppearance;
class LLTabContainer;
@@ -63,6 +65,13 @@ public:
bool isCOFPanelActive() const;
+ void setMenuButtons(
+ LLMenuButton* gear_menu,
+ LLMenuButton* sort_menu,
+ LLButton* trash_btn,
+ LLPanel* sort_menu_panel,
+ LLPanel* trash_menu_panel);
+
protected:
void updateVerbs();
@@ -92,20 +101,29 @@ protected:
void initListCommandsHandlers();
void updateListCommands();
void onWearButtonClick();
- void showGearMenu();
void onTrashButtonClick();
+ void onGearMouseDown();
bool isActionEnabled(const LLSD& userdata);
void setWearablesLoading(bool val);
void onWearablesLoaded();
void onWearablesLoading();
private:
LLPanel* mListCommands;
- LLMenuGL* mMenuAdd;
LLButton* mWearBtn = nullptr;
// List Commands //
//////////////////////////////////////////////////////////////////////////////////
bool mInitialized;
+
+ // not owned items
+ LLMenuButton* mGearMenu;
+ LLMenuButton* mSortMenu;
+ LLButton* mTrashBtn;
+ LLPanel* mSortMenuPanel;
+ LLPanel* mTrashMenuPanel;
+ boost::signals2::connection mGearMenuConnection;
+ boost::signals2::connection mSortMenuConnection;
+ boost::signals2::connection mTrashMenuConnection;
};
#endif //LL_LLPANELOUTFITSINVENTORY_H
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 366c80f580..4b9f109558 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -308,10 +308,10 @@ public:
: LLEventTimer(period),
LLPanelPeople::Updater(cb)
{
- mEventTimer.stop();
+ stop();
}
- virtual bool tick() // from LLEventTimer
+ bool tick() override // from LLEventTimer
{
return false;
}
@@ -348,13 +348,13 @@ public:
LLAvatarTracker::instance().removeObserver(this);
}
- /*virtual*/ void changed(U32 mask)
+ void changed(U32 mask) override
{
if (mIsActive)
{
// events can arrive quickly in bulk - we need not process EVERY one of them -
// so we wait a short while to let others pile-in, and process them in aggregate.
- mEventTimer.start();
+ start();
}
// save-up all the mask-bits which have come-in
@@ -362,7 +362,7 @@ public:
}
- /*virtual*/ bool tick()
+ bool tick() override
{
if (!mIsActive) return false;
@@ -372,14 +372,13 @@ public:
}
// Stop updates.
- mEventTimer.stop();
+ stop();
mMask = 0;
return false;
}
- // virtual
- void setActive(bool active)
+ void setActive(bool active) override
{
mIsActive = active;
if (active)
@@ -488,22 +487,22 @@ public:
setActive(false);
}
- /*virtual*/ void setActive(bool val)
+ void setActive(bool val) override
{
if (val)
{
// update immediately and start regular updates
update();
- mEventTimer.start();
+ start();
}
else
{
// stop regular updates
- mEventTimer.stop();
+ stop();
}
}
- /*virtual*/ bool tick()
+ bool tick() override
{
update();
return false;
@@ -543,18 +542,18 @@ LLPanelPeople::LLPanelPeople()
mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this));
mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this));
- mCommitCallbackRegistrar.add("People.AddFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this));
- mCommitCallbackRegistrar.add("People.AddFriendWizard", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this));
- mCommitCallbackRegistrar.add("People.DelFriend", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this));
- mCommitCallbackRegistrar.add("People.Group.Minus", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this));
- mCommitCallbackRegistrar.add("People.Chat", boost::bind(&LLPanelPeople::onChatButtonClicked, this));
- mCommitCallbackRegistrar.add("People.Gear", boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1));
-
- mCommitCallbackRegistrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2));
- mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2));
- mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2));
- mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2));
- mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2));
+ mCommitCallbackRegistrar.add("People.AddFriend", { boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this) });
+ mCommitCallbackRegistrar.add("People.AddFriendWizard", { boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this) });
+ mCommitCallbackRegistrar.add("People.DelFriend", { boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("People.Group.Minus", { boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("People.Chat", { boost::bind(&LLPanelPeople::onChatButtonClicked, this) });
+ mCommitCallbackRegistrar.add("People.Gear", { boost::bind(&LLPanelPeople::onGearButtonClicked, this, _1) });
+
+ mCommitCallbackRegistrar.add("People.Group.Plus.Action", { boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("People.Friends.ViewSort.Action", { boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2) });
+ mCommitCallbackRegistrar.add("People.Nearby.ViewSort.Action", { boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2) });
+ mCommitCallbackRegistrar.add("People.Groups.ViewSort.Action", { boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2) });
+ mCommitCallbackRegistrar.add("People.Recent.ViewSort.Action", { boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2) });
mEnableCallbackRegistrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2));
mEnableCallbackRegistrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2));
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 04b8af49c1..3b42b60c0f 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -58,7 +58,7 @@ NearbyPeopleContextMenu gNearbyPeopleContextMenu;
LLContextMenu* PeopleContextMenu::createMenu()
{
// set up the callbacks for all of the avatar menu items
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
LLContextMenu* menu;
@@ -68,22 +68,22 @@ LLContextMenu* PeopleContextMenu::createMenu()
const LLUUID& id = mUUIDs.front();
registrar.add("Avatar.Profile", boost::bind(&LLAvatarActions::showProfile, id));
- registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, id));
- registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendDialog, id));
+ registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, id), LLUICtrl::cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendDialog, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startIM, id));
- registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id));
- registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this));
+ registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
registrar.add("Avatar.ZoomIn", boost::bind(&handle_zoom_to_object, id));
registrar.add("Avatar.TeleportTo", boost::bind(&handle_teleport_to_object, id));
registrar.add("Avatar.ShowOnMap", boost::bind(&LLAvatarActions::showOnMap, id));
- registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id));
- registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id));
+ registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, id));
- registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id));
+ registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id), LLUICtrl::cb_info::UNTRUSTED_BLOCK);
registrar.add("Avatar.TeleportRequest", boost::bind(&PeopleContextMenu::requestTeleport, this));
- registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id));
- registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::freezeAvatar, id));
- registrar.add("Avatar.Eject", boost::bind(&PeopleContextMenu::eject, this));
+ registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id), LLUICtrl::cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::freezeAvatar, id), LLUICtrl::cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("Avatar.Eject", boost::bind(&PeopleContextMenu::eject, this), LLUICtrl::cb_info::UNTRUSTED_THROTTLE);
enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2));
@@ -351,7 +351,10 @@ void PeopleContextMenu::eject()
avatar = (LLVOAvatar*) object;
}
}
- if (!avatar) return;
+
+ if (!avatar)
+ return;
+
LLSD payload;
payload["avatar_id"] = avatar->getID();
std::string fullname = avatar->getFullname();
diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp
index 0ce1f0f9d3..891896076a 100644
--- a/indra/newview/llpanelpermissions.cpp
+++ b/indra/newview/llpanelpermissions.cpp
@@ -176,7 +176,7 @@ bool LLPanelPermissions::postBuild()
childSetCommitCallback("sale type",LLPanelPermissions::onCommitSaleType,this);
- childSetCommitCallback("Edit Cost", LLPanelPermissions::onCommitSaleInfo, this);
+ childSetCommitCallback("Edit Cost", LLPanelPermissions::onCommitSalePrice, this);
childSetCommitCallback("checkbox next owner can modify",LLPanelPermissions::onCommitNextOwnerModify,this);
childSetCommitCallback("checkbox next owner can copy",LLPanelPermissions::onCommitNextOwnerCopy,this);
@@ -781,7 +781,9 @@ void LLPanelPermissions::refresh()
if (has_change_sale_ability && (owner_mask_on & PERM_TRANSFER))
{
- getChildView("checkbox for sale")->setEnabled(can_transfer || (!can_transfer && num_for_sale));
+ bool change_sale_allowed = can_transfer || (!can_transfer && num_for_sale);
+ getChildView("checkbox for sale")->setEnabled(change_sale_allowed);
+ getChildView("Edit Cost")->setEnabled(change_sale_allowed && !is_for_sale_mixed);
// Set the checkbox to tentative if the prices of each object selected
// are not the same.
getChild<LLUICtrl>("checkbox for sale")->setTentative( is_for_sale_mixed);
@@ -1223,6 +1225,16 @@ void LLPanelPermissions::onCommitSaleType(LLUICtrl*, void* data)
self->setAllSaleInfo();
}
+void LLPanelPermissions::onCommitSalePrice(LLUICtrl *, void *data)
+{
+ LLPanelPermissions *self = (LLPanelPermissions *) data;
+ LLCheckBoxCtrl *checkPurchase = self->getChild<LLCheckBoxCtrl>("checkbox for sale");
+ if (checkPurchase && checkPurchase->get())
+ {
+ self->setAllSaleInfo();
+ }
+}
+
void LLPanelPermissions::setAllSaleInfo()
{
LL_INFOS() << "LLPanelPermissions::setAllSaleInfo()" << LL_ENDL;
diff --git a/indra/newview/llpanelpermissions.h b/indra/newview/llpanelpermissions.h
index 77129434ed..12e88361c9 100644
--- a/indra/newview/llpanelpermissions.h
+++ b/indra/newview/llpanelpermissions.h
@@ -77,6 +77,7 @@ protected:
static void onCommitSaleInfo(LLUICtrl* ctrl, void* data);
static void onCommitSaleType(LLUICtrl* ctrl, void* data);
+ static void onCommitSalePrice(LLUICtrl *ctrl, void *data);
void setAllSaleInfo();
static void onCommitClickAction(LLUICtrl* ctrl, void*);
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 7deb1d9fd4..5fb20d4b69 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -315,7 +315,7 @@ bool LLPanelPlaces::postBuild()
, _7 // EAcceptance* accept
));
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ ScopedRegistrarHelper registrar;
registrar.add("Places.OverflowMenu.Action", boost::bind(&LLPanelPlaces::onOverflowMenuItemClicked, this, _2));
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
enable_registrar.add("Places.OverflowMenu.Enable", boost::bind(&LLPanelPlaces::onOverflowMenuItemEnable, this, _2));
diff --git a/indra/newview/llpanelpresetscamerapulldown.cpp b/indra/newview/llpanelpresetscamerapulldown.cpp
index 5b0aa28223..d1497719e0 100644
--- a/indra/newview/llpanelpresetscamerapulldown.cpp
+++ b/indra/newview/llpanelpresetscamerapulldown.cpp
@@ -48,8 +48,8 @@
// Default constructor
LLPanelPresetsCameraPulldown::LLPanelPresetsCameraPulldown()
{
- mCommitCallbackRegistrar.add("Presets.toggleCameraFloater", boost::bind(&LLPanelPresetsCameraPulldown::onViewButtonClick, this, _2));
- mCommitCallbackRegistrar.add("PresetsCamera.RowClick", boost::bind(&LLPanelPresetsCameraPulldown::onRowClick, this, _2));
+ mCommitCallbackRegistrar.add("Presets.toggleCameraFloater", { boost::bind(&LLPanelPresetsCameraPulldown::onViewButtonClick, this, _2) });
+ mCommitCallbackRegistrar.add("PresetsCamera.RowClick", { boost::bind(&LLPanelPresetsCameraPulldown::onRowClick, this, _2) });
buildFromFile( "panel_presets_camera_pulldown.xml");
}
diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp
index 3b0f1273df..3d564ef540 100644
--- a/indra/newview/llpanelpresetspulldown.cpp
+++ b/indra/newview/llpanelpresetspulldown.cpp
@@ -50,9 +50,9 @@ LLPanelPresetsPulldown::LLPanelPresetsPulldown()
{
mHoverTimer.stop();
- mCommitCallbackRegistrar.add("Presets.GoGraphicsPrefs", boost::bind(&LLPanelPresetsPulldown::onGraphicsButtonClick, this, _2));
- mCommitCallbackRegistrar.add("Presets.GoAutofpsPrefs", boost::bind(&LLPanelPresetsPulldown::onAutofpsButtonClick, this, _2));
- mCommitCallbackRegistrar.add("Presets.RowClick", boost::bind(&LLPanelPresetsPulldown::onRowClick, this, _2));
+ mCommitCallbackRegistrar.add("Presets.GoGraphicsPrefs", { boost::bind(&LLPanelPresetsPulldown::onGraphicsButtonClick, this, _2) });
+ mCommitCallbackRegistrar.add("Presets.GoAutofpsPrefs", { boost::bind(&LLPanelPresetsPulldown::onAutofpsButtonClick, this, _2) });
+ mCommitCallbackRegistrar.add("Presets.RowClick", { boost::bind(&LLPanelPresetsPulldown::onRowClick, this, _2) });
buildFromFile( "panel_presets_pulldown.xml");
}
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index 4db0a5b59d..955b5e7730 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -101,28 +101,28 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() :
mSecureURL(false),
mMediaPlaySliderCtrlMouseDownValue(0.0)
{
- mCommitCallbackRegistrar.add("MediaCtrl.Close", boost::bind(&LLPanelPrimMediaControls::onClickClose, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Back", boost::bind(&LLPanelPrimMediaControls::onClickBack, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Forward", boost::bind(&LLPanelPrimMediaControls::onClickForward, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Home", boost::bind(&LLPanelPrimMediaControls::onClickHome, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Stop", boost::bind(&LLPanelPrimMediaControls::onClickStop, this));
- mCommitCallbackRegistrar.add("MediaCtrl.MediaStop", boost::bind(&LLPanelPrimMediaControls::onClickMediaStop, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Reload", boost::bind(&LLPanelPrimMediaControls::onClickReload, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Play", boost::bind(&LLPanelPrimMediaControls::onClickPlay, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Pause", boost::bind(&LLPanelPrimMediaControls::onClickPause, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Open", boost::bind(&LLPanelPrimMediaControls::onClickOpen, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Zoom", boost::bind(&LLPanelPrimMediaControls::onClickZoom, this));
- mCommitCallbackRegistrar.add("MediaCtrl.CommitURL", boost::bind(&LLPanelPrimMediaControls::onCommitURL, this));
- mCommitCallbackRegistrar.add("MediaCtrl.MouseDown", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown, this));
- mCommitCallbackRegistrar.add("MediaCtrl.MouseUp", boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp, this));
- mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this));
- mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this));
- mCommitCallbackRegistrar.add("MediaCtrl.Volume", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeSlider, this));
- mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute", boost::bind(&LLPanelPrimMediaControls::onToggleMute, this));
- mCommitCallbackRegistrar.add("MediaCtrl.ShowVolumeSlider", boost::bind(&LLPanelPrimMediaControls::showVolumeSlider, this));
- mCommitCallbackRegistrar.add("MediaCtrl.HideVolumeSlider", boost::bind(&LLPanelPrimMediaControls::hideVolumeSlider, this));
- mCommitCallbackRegistrar.add("MediaCtrl.SkipBack", boost::bind(&LLPanelPrimMediaControls::onClickSkipBack, this));
- mCommitCallbackRegistrar.add("MediaCtrl.SkipForward", boost::bind(&LLPanelPrimMediaControls::onClickSkipForward, this));
+ mCommitCallbackRegistrar.add("MediaCtrl.Close", { boost::bind(&LLPanelPrimMediaControls::onClickClose, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Back", { boost::bind(&LLPanelPrimMediaControls::onClickBack, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Forward", { boost::bind(&LLPanelPrimMediaControls::onClickForward, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Home", { boost::bind(&LLPanelPrimMediaControls::onClickHome, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Stop", { boost::bind(&LLPanelPrimMediaControls::onClickStop, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.MediaStop", { boost::bind(&LLPanelPrimMediaControls::onClickMediaStop, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Reload", { boost::bind(&LLPanelPrimMediaControls::onClickReload, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Play", { boost::bind(&LLPanelPrimMediaControls::onClickPlay, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Pause", { boost::bind(&LLPanelPrimMediaControls::onClickPause, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Open", { boost::bind(&LLPanelPrimMediaControls::onClickOpen, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Zoom", { boost::bind(&LLPanelPrimMediaControls::onClickZoom, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.CommitURL", { boost::bind(&LLPanelPrimMediaControls::onCommitURL, this), LLUICtrl::cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("MediaCtrl.MouseDown", { boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseDown, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.MouseUp", { boost::bind(&LLPanelPrimMediaControls::onMediaPlaySliderCtrlMouseUp, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp", { boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown", { boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.Volume", { boost::bind(&LLPanelPrimMediaControls::onCommitVolumeSlider, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute", { boost::bind(&LLPanelPrimMediaControls::onToggleMute, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.ShowVolumeSlider", { boost::bind(&LLPanelPrimMediaControls::showVolumeSlider, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.HideVolumeSlider", { boost::bind(&LLPanelPrimMediaControls::hideVolumeSlider, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.SkipBack", { boost::bind(&LLPanelPrimMediaControls::onClickSkipBack, this) });
+ mCommitCallbackRegistrar.add("MediaCtrl.SkipForward", { boost::bind(&LLPanelPrimMediaControls::onClickSkipForward, this) });
buildFromFile( "panel_prim_media_controls.xml");
mInactivityTimer.reset();
@@ -777,7 +777,7 @@ void LLPanelPrimMediaControls::draw()
else if(mFadeTimer.getStarted())
{
F32 time = mFadeTimer.getElapsedTimeF32();
- alpha *= llmax(lerp(1.0, 0.0, time / mControlFadeTime), 0.0f);
+ alpha *= llmax(lerp(1.0f, 0.0f, time / mControlFadeTime), 0.0f);
if(time >= mControlFadeTime)
{
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 132098ba99..d72d28869d 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -754,8 +754,6 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key)
resetData();
- LLUUID avatar_id = getAvatarId();
-
bool own_profile = getSelfProfile();
mGroupList->setShowNone(!own_profile);
@@ -772,7 +770,7 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key)
}
// Init menu, menu needs to be created in scope of a registar to work correctly.
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit;
+ ScopedRegistrarHelper commit;
commit.add("Profile.Commit", [this](LLUICtrl*, const LLSD& userdata) { onCommitMenu(userdata); });
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable;
@@ -793,7 +791,6 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key)
if (!own_profile)
{
- mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(avatar_id) ? LLAvatarTracker::instance().isBuddyOnline(avatar_id) : true);
updateOnlineStatus();
fillRightsData();
}
@@ -1214,17 +1211,6 @@ void LLPanelProfileSecondLife::changed(U32 mask)
}
}
-// virtual, called by LLVoiceClient
-void LLPanelProfileSecondLife::onChange(EStatusType status, const LLSD& channelInfo, bool proximal)
-{
- if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
- {
- return;
- }
-
- mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(getAvatarId()) ? LLAvatarTracker::instance().isBuddyOnline(getAvatarId()) : true);
-}
-
void LLPanelProfileSecondLife::setAvatarId(const LLUUID& avatar_id)
{
if (avatar_id.notNull())
@@ -1507,7 +1493,7 @@ bool LLPanelProfileSecondLife::onEnableMenu(const LLSD& userdata)
}
else if (item_name == "voice_call")
{
- return mVoiceStatus;
+ return LLAvatarActions::canCallTo(agent_id);
}
else if (item_name == "chat_history")
{
@@ -2071,6 +2057,7 @@ void LLPanelProfileFirstLife::onChangePhoto()
}
});
texture_floaterp->setLocalTextureEnabled(false);
+ texture_floaterp->setBakeTextureEnabled(false);
texture_floaterp->setCanApply(false, true, false);
parent_floater->addDependentFloater(mFloaterTexturePickerHandle);
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index c207a4162a..ba00e12441 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -33,7 +33,6 @@
#include "llpanel.h"
#include "llpanelavatar.h"
#include "llmediactrl.h"
-#include "llvoiceclient.h"
// class LLPanelProfileClassifieds;
// class LLTabContainer;
@@ -70,7 +69,6 @@ class LLViewerFetchedTexture;
class LLPanelProfileSecondLife
: public LLPanelProfilePropertiesProcessorTab
, public LLFriendObserver
- , public LLVoiceClientStatusObserver
{
public:
LLPanelProfileSecondLife();
@@ -89,10 +87,6 @@ public:
*/
void changed(U32 mask) override;
- // Implements LLVoiceClientStatusObserver::onChange() to enable the call
- // button when voice is available
- void onChange(EStatusType status, const LLSD& channelInfo, bool proximal) override;
-
void setAvatarId(const LLUUID& avatar_id) override;
bool postBuild() override;
@@ -203,7 +197,6 @@ private:
LLHandle<LLFloater> mFloaterTexturePickerHandle;
bool mHasUnsavedDescriptionChanges;
- bool mVoiceStatus;
bool mWaitingForImageUpload;
bool mAllowPublish;
bool mHideAge;
diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h
index 42cd5f8975..2e6b7c4428 100644
--- a/indra/newview/llpanelprofileclassifieds.h
+++ b/indra/newview/llpanelprofileclassifieds.h
@@ -157,17 +157,17 @@ public:
void setParcelId(const LLUUID& id) { mParcelId = id; }
- LLUUID getParcelId() { return mParcelId; }
+ LLUUID getParcelId() const { return mParcelId; }
void setSimName(const std::string& sim_name) { mSimName = sim_name; }
- std::string getSimName() { return mSimName; }
+ std::string getSimName() const { return mSimName; }
void setFromSearch(bool val) { mFromSearch = val; }
- bool fromSearch() { return mFromSearch; }
+ bool fromSearch() const { return mFromSearch; }
- bool getInfoLoaded() { return mInfoLoaded; }
+ bool getInfoLoaded() const { return mInfoLoaded; }
void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; }
@@ -175,9 +175,9 @@ public:
void resetDirty() override;
- bool isNew() { return mIsNew; }
+ bool isNew() const { return mIsNew; }
- bool isNewWithErrors() { return mIsNewWithErrors; }
+ bool isNewWithErrors() const { return mIsNewWithErrors; }
bool canClose();
@@ -191,10 +191,10 @@ public:
bool getAutoRenew();
- S32 getPriceForListing() { return mPriceForListing; }
+ S32 getPriceForListing() const { return mPriceForListing; }
void setEditMode(bool edit_mode);
- bool getEditMode() {return mEditMode;}
+ bool getEditMode() const { return mEditMode; }
static void setClickThrough(
const LLUUID& classified_id,
diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp
index 08f3d3af5a..11a10ebd2c 100644
--- a/indra/newview/llpanelprofilepicks.cpp
+++ b/indra/newview/llpanelprofilepicks.cpp
@@ -246,6 +246,8 @@ void LLPanelProfilePicks::onClickNewBtn()
select_tab(true).
label(pick_panel->getPickName()));
updateButtons();
+
+ pick_panel->addLocationChangedCallbacks();
}
void LLPanelProfilePicks::onClickDelete()
@@ -571,10 +573,12 @@ void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id)
{
mPickName->setEnabled(true);
mPickDescription->setEnabled(true);
+ mSetCurrentLocationButton->setVisible(true);
}
else
{
mSnapshotCtrl->setEnabled(false);
+ mSetCurrentLocationButton->setVisible(false);
}
}
@@ -585,6 +589,7 @@ bool LLPanelProfilePick::postBuild()
mSaveButton = getChild<LLButton>("save_changes_btn");
mCreateButton = getChild<LLButton>("create_changes_btn");
mCancelButton = getChild<LLButton>("cancel_changes_btn");
+ mSetCurrentLocationButton = getChild<LLButton>("set_to_curr_location_btn");
mSnapshotCtrl = getChild<LLTextureCtrl>("pick_snapshot");
mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this));
@@ -597,6 +602,7 @@ bool LLPanelProfilePick::postBuild()
mSaveButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this));
mCreateButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this));
mCancelButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickCancel, this));
+ mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this));
mPickName->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1), NULL);
mPickName->setEnabled(false);
@@ -759,6 +765,32 @@ bool LLPanelProfilePick::isDirty() const
return false;
}
+void LLPanelProfilePick::onClickSetLocation()
+{
+ // Save location for later use.
+ setPosGlobal(gAgent.getPositionGlobal());
+
+ std::string parcel_name, region_name;
+
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (parcel)
+ {
+ mParcelId = parcel->getID();
+ parcel_name = parcel->getName();
+ }
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ region_name = region->getName();
+ }
+
+ setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal()));
+
+ mLocationChanged = true;
+ enableSaveButton(true);
+}
+
void LLPanelProfilePick::onClickSave()
{
if (mRegionCallbackConnection.connected())
@@ -769,6 +801,10 @@ void LLPanelProfilePick::onClickSave()
{
mParcelCallbackConnection.disconnect();
}
+ if (mLocationChanged)
+ {
+ onClickSetLocation();
+ }
sendUpdate();
mLocationChanged = false;
@@ -816,6 +852,12 @@ void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data)
}
}
+void LLPanelProfilePick::addLocationChangedCallbacks()
+{
+ mRegionCallbackConnection = gAgent.addRegionChangedCallback([this]() { onClickSetLocation(); });
+ mParcelCallbackConnection = gAgent.addParcelChangedCallback([this]() { onClickSetLocation(); });
+}
+
void LLPanelProfilePick::sendUpdate()
{
LLPickData pick_data;
diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h
index e3f50f5576..5e5d4ff81e 100644
--- a/indra/newview/llpanelprofilepicks.h
+++ b/indra/newview/llpanelprofilepicks.h
@@ -138,6 +138,8 @@ public:
void setParcelID(const LLUUID& parcel_id) override { mParcelId = parcel_id; }
void setErrorStatus(S32 status, const std::string& reason) override {};
+ void addLocationChangedCallbacks();
+
protected:
/**
@@ -200,6 +202,11 @@ public:
void resetDirty() override;
/**
+ * Callback for "Set Location" button click
+ */
+ void onClickSetLocation();
+
+ /**
* Callback for "Save" and "Create" button click
*/
void onClickSave();
@@ -221,6 +228,7 @@ protected:
LLTextureCtrl* mSnapshotCtrl;
LLLineEditor* mPickName;
LLTextEditor* mPickDescription;
+ LLButton* mSetCurrentLocationButton;
LLButton* mSaveButton;
LLButton* mCreateButton;
LLButton* mCancelButton;
@@ -236,7 +244,7 @@ protected:
bool mLocationChanged;
bool mNewPick;
- bool mIsEditing;
+ bool mIsEditing;
void onDescriptionFocusReceived();
};
diff --git a/indra/newview/llpanelsnapshot.cpp b/indra/newview/llpanelsnapshot.cpp
index 32c9f6f402..56c0294dbe 100644
--- a/indra/newview/llpanelsnapshot.cpp
+++ b/indra/newview/llpanelsnapshot.cpp
@@ -37,6 +37,7 @@
// newview
#include "llsidetraypanelcontainer.h"
+#include "llsnapshotlivepreview.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llagentbenefits.h"
@@ -99,6 +100,17 @@ void LLPanelSnapshot::onOpen(const LLSD& key)
{
getParentByType<LLFloater>()->notify(LLSD().with("image-format-change", true));
}
+
+ // If resolution is set to "Current Window", force a snapshot update
+ // each time a snapshot panel is opened to determine the correct
+ // image size (and upload fee) depending on the snapshot type.
+ if (mSnapshotFloater && getChild<LLUICtrl>(getImageSizeComboName())->getValue().asString() == "[i0,i0]")
+ {
+ if (LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView())
+ {
+ preview->mForceUpdateSnapshot = true;
+ }
+ }
}
LLSnapshotModel::ESnapshotFormat LLPanelSnapshot::getImageFormat() const
diff --git a/indra/newview/llpanelsnapshotinventory.cpp b/indra/newview/llpanelsnapshotinventory.cpp
index 96b17acc40..dda14c1e32 100644
--- a/indra/newview/llpanelsnapshotinventory.cpp
+++ b/indra/newview/llpanelsnapshotinventory.cpp
@@ -42,85 +42,43 @@
/**
* The panel provides UI for saving snapshot as an inventory texture.
*/
-class LLPanelSnapshotInventoryBase
- : public LLPanelSnapshot
-{
- LOG_CLASS(LLPanelSnapshotInventoryBase);
-
-public:
- LLPanelSnapshotInventoryBase();
-
- /*virtual*/ bool postBuild();
-protected:
- void onSend();
- /*virtual*/ LLSnapshotModel::ESnapshotType getSnapshotType();
-};
-
class LLPanelSnapshotInventory
- : public LLPanelSnapshotInventoryBase
+ : public LLPanelSnapshot
{
LOG_CLASS(LLPanelSnapshotInventory);
public:
LLPanelSnapshotInventory();
- /*virtual*/ bool postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
+ bool postBuild() override;
+ void onOpen(const LLSD& key) override;
void onResolutionCommit(LLUICtrl* ctrl);
private:
- /*virtual*/ std::string getWidthSpinnerName() const { return "inventory_snapshot_width"; }
- /*virtual*/ std::string getHeightSpinnerName() const { return "inventory_snapshot_height"; }
- /*virtual*/ std::string getAspectRatioCBName() const { return "inventory_keep_aspect_check"; }
- /*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; }
- /*virtual*/ std::string getImageSizePanelName() const { return LLStringUtil::null; }
- /*virtual*/ void updateControls(const LLSD& info);
-
-};
-
-class LLPanelOutfitSnapshotInventory
- : public LLPanelSnapshotInventoryBase
-{
- LOG_CLASS(LLPanelOutfitSnapshotInventory);
-
-public:
- LLPanelOutfitSnapshotInventory();
- /*virtual*/ bool postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
+ std::string getWidthSpinnerName() const override { return "inventory_snapshot_width"; }
+ std::string getHeightSpinnerName() const override { return "inventory_snapshot_height"; }
+ std::string getAspectRatioCBName() const override { return "inventory_keep_aspect_check"; }
+ std::string getImageSizeComboName() const override { return "texture_size_combo"; }
+ std::string getImageSizePanelName() const override { return LLStringUtil::null; }
+ LLSnapshotModel::ESnapshotType getSnapshotType() override;
+ void updateControls(const LLSD& info) override;
-private:
- /*virtual*/ std::string getWidthSpinnerName() const { return ""; }
- /*virtual*/ std::string getHeightSpinnerName() const { return ""; }
- /*virtual*/ std::string getAspectRatioCBName() const { return ""; }
- /*virtual*/ std::string getImageSizeComboName() const { return "texture_size_combo"; }
- /*virtual*/ std::string getImageSizePanelName() const { return LLStringUtil::null; }
- /*virtual*/ void updateControls(const LLSD& info);
-
- /*virtual*/ void cancel();
+ void onSend();
+ void updateUploadCost();
+ S32 calculateUploadCost();
};
static LLPanelInjector<LLPanelSnapshotInventory> panel_class1("llpanelsnapshotinventory");
-static LLPanelInjector<LLPanelOutfitSnapshotInventory> panel_class2("llpaneloutfitsnapshotinventory");
-
-LLPanelSnapshotInventoryBase::LLPanelSnapshotInventoryBase()
-{
-}
-
-bool LLPanelSnapshotInventoryBase::postBuild()
-{
- return LLPanelSnapshot::postBuild();
-}
-
-LLSnapshotModel::ESnapshotType LLPanelSnapshotInventoryBase::getSnapshotType()
+LLSnapshotModel::ESnapshotType LLPanelSnapshotInventory::getSnapshotType()
{
return LLSnapshotModel::SNAPSHOT_TEXTURE;
}
LLPanelSnapshotInventory::LLPanelSnapshotInventory()
{
- mCommitCallbackRegistrar.add("Inventory.Save", boost::bind(&LLPanelSnapshotInventory::onSend, this));
- mCommitCallbackRegistrar.add("Inventory.Cancel", boost::bind(&LLPanelSnapshotInventory::cancel, this));
+ mCommitCallbackRegistrar.add("Inventory.Save", { boost::bind(&LLPanelSnapshotInventory::onSend, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("Inventory.Cancel", { boost::bind(&LLPanelSnapshotInventory::cancel, this), cb_info::UNTRUSTED_BLOCK });
}
// virtual
@@ -130,12 +88,14 @@ bool LLPanelSnapshotInventory::postBuild()
getChild<LLSpinCtrl>(getHeightSpinnerName())->setAllowEdit(false);
getChild<LLUICtrl>(getImageSizeComboName())->setCommitCallback(boost::bind(&LLPanelSnapshotInventory::onResolutionCommit, this, _1));
- return LLPanelSnapshotInventoryBase::postBuild();
+ return LLPanelSnapshot::postBuild();
}
// virtual
void LLPanelSnapshotInventory::onOpen(const LLSD& key)
{
+ updateUploadCost();
+
LLPanelSnapshot::onOpen(key);
}
@@ -144,6 +104,8 @@ void LLPanelSnapshotInventory::updateControls(const LLSD& info)
{
const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
getChild<LLUICtrl>("save_btn")->setEnabled(have_snapshot);
+
+ updateUploadCost();
}
void LLPanelSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl)
@@ -153,21 +115,9 @@ void LLPanelSnapshotInventory::onResolutionCommit(LLUICtrl* ctrl)
getChild<LLSpinCtrl>(getHeightSpinnerName())->setVisible(!current_window_selected);
}
-void LLPanelSnapshotInventoryBase::onSend()
+void LLPanelSnapshotInventory::onSend()
{
- S32 w = 0;
- S32 h = 0;
-
- if( mSnapshotFloater )
- {
- LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView();
- if( preview )
- {
- preview->getSize(w, h);
- }
- }
-
- S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(w, h);
+ S32 expected_upload_cost = calculateUploadCost();
if (can_afford_transaction(expected_upload_cost))
{
if (mSnapshotFloater)
@@ -188,36 +138,24 @@ void LLPanelSnapshotInventoryBase::onSend()
}
}
-LLPanelOutfitSnapshotInventory::LLPanelOutfitSnapshotInventory()
+void LLPanelSnapshotInventory::updateUploadCost()
{
- mCommitCallbackRegistrar.add("Inventory.SaveOutfitPhoto", boost::bind(&LLPanelOutfitSnapshotInventory::onSend, this));
- mCommitCallbackRegistrar.add("Inventory.SaveOutfitCancel", boost::bind(&LLPanelOutfitSnapshotInventory::cancel, this));
+ getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", calculateUploadCost()));
}
-// virtual
-bool LLPanelOutfitSnapshotInventory::postBuild()
+S32 LLPanelSnapshotInventory::calculateUploadCost()
{
- return LLPanelSnapshotInventoryBase::postBuild();
-}
-
-// virtual
-void LLPanelOutfitSnapshotInventory::onOpen(const LLSD& key)
-{
- getChild<LLUICtrl>("hint_lbl")->setTextArg("[UPLOAD_COST]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost()));
- LLPanelSnapshot::onOpen(key);
-}
-
-// virtual
-void LLPanelOutfitSnapshotInventory::updateControls(const LLSD& info)
-{
- const bool have_snapshot = info.has("have-snapshot") ? info["have-snapshot"].asBoolean() : true;
- getChild<LLUICtrl>("save_btn")->setEnabled(have_snapshot);
-}
+ S32 w = 0;
+ S32 h = 0;
-void LLPanelOutfitSnapshotInventory::cancel()
-{
if (mSnapshotFloater)
{
- mSnapshotFloater->closeFloater();
+ if (LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView())
+ {
+ w = preview->getEncodedImageWidth();
+ h = preview->getEncodedImageHeight();
+ }
}
+
+ return LLAgentBenefitsMgr::current().getTextureUploadCost(w, h);
}
diff --git a/indra/newview/llpanelsnapshotlocal.cpp b/indra/newview/llpanelsnapshotlocal.cpp
index 366030c0fa..d1807ca3f8 100644
--- a/indra/newview/llpanelsnapshotlocal.cpp
+++ b/indra/newview/llpanelsnapshotlocal.cpp
@@ -47,18 +47,18 @@ class LLPanelSnapshotLocal
public:
LLPanelSnapshotLocal();
- /*virtual*/ bool postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
+ bool postBuild() override;
+ void onOpen(const LLSD& key) override;
private:
- /*virtual*/ std::string getWidthSpinnerName() const { return "local_snapshot_width"; }
- /*virtual*/ std::string getHeightSpinnerName() const { return "local_snapshot_height"; }
- /*virtual*/ std::string getAspectRatioCBName() const { return "local_keep_aspect_check"; }
- /*virtual*/ std::string getImageSizeComboName() const { return "local_size_combo"; }
- /*virtual*/ std::string getImageSizePanelName() const { return "local_image_size_lp"; }
- /*virtual*/ LLSnapshotModel::ESnapshotFormat getImageFormat() const;
- /*virtual*/ LLSnapshotModel::ESnapshotType getSnapshotType();
- /*virtual*/ void updateControls(const LLSD& info);
+ std::string getWidthSpinnerName() const override { return "local_snapshot_width"; }
+ std::string getHeightSpinnerName() const override { return "local_snapshot_height"; }
+ std::string getAspectRatioCBName() const override { return "local_keep_aspect_check"; }
+ std::string getImageSizeComboName() const override { return "local_size_combo"; }
+ std::string getImageSizePanelName() const override { return "local_image_size_lp"; }
+ LLSnapshotModel::ESnapshotFormat getImageFormat() const override;
+ LLSnapshotModel::ESnapshotType getSnapshotType() override;
+ void updateControls(const LLSD& info) override;
S32 mLocalFormat;
@@ -75,7 +75,7 @@ static LLPanelInjector<LLPanelSnapshotLocal> panel_class("llpanelsnapshotlocal")
LLPanelSnapshotLocal::LLPanelSnapshotLocal()
{
mLocalFormat = gSavedSettings.getS32("SnapshotFormat");
- mCommitCallbackRegistrar.add("Local.Cancel", boost::bind(&LLPanelSnapshotLocal::cancel, this));
+ mCommitCallbackRegistrar.add("Local.Cancel", { boost::bind(&LLPanelSnapshotLocal::cancel, this) });
}
// virtual
diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp
index 962d3bba16..eadf8df188 100644
--- a/indra/newview/llpanelsnapshotoptions.cpp
+++ b/indra/newview/llpanelsnapshotoptions.cpp
@@ -30,12 +30,8 @@
#include "llsidetraypanelcontainer.h"
#include "llfloatersnapshot.h" // FIXME: create a snapshot model
-#include "llsnapshotlivepreview.h"
#include "llfloaterreg.h"
-#include "llagentbenefits.h"
-
-
/**
* Provides several ways to save a snapshot.
*/
@@ -46,12 +42,9 @@ class LLPanelSnapshotOptions
public:
LLPanelSnapshotOptions();
- ~LLPanelSnapshotOptions();
- /*virtual*/ bool postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
+ bool postBuild() override;
private:
- void updateUploadCost();
void openPanel(const std::string& panel_name);
void onSaveToProfile();
void onSaveToEmail();
@@ -65,14 +58,10 @@ static LLPanelInjector<LLPanelSnapshotOptions> panel_class("llpanelsnapshotoptio
LLPanelSnapshotOptions::LLPanelSnapshotOptions()
{
- mCommitCallbackRegistrar.add("Snapshot.SaveToProfile", boost::bind(&LLPanelSnapshotOptions::onSaveToProfile, this));
- mCommitCallbackRegistrar.add("Snapshot.SaveToEmail", boost::bind(&LLPanelSnapshotOptions::onSaveToEmail, this));
- mCommitCallbackRegistrar.add("Snapshot.SaveToInventory", boost::bind(&LLPanelSnapshotOptions::onSaveToInventory, this));
- mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this));
-}
-
-LLPanelSnapshotOptions::~LLPanelSnapshotOptions()
-{
+ mCommitCallbackRegistrar.add("Snapshot.SaveToProfile", { boost::bind(&LLPanelSnapshotOptions::onSaveToProfile, this) });
+ mCommitCallbackRegistrar.add("Snapshot.SaveToEmail", { boost::bind(&LLPanelSnapshotOptions::onSaveToEmail, this) });
+ mCommitCallbackRegistrar.add("Snapshot.SaveToInventory", { boost::bind(&LLPanelSnapshotOptions::onSaveToInventory, this) });
+ mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", { boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this) });
}
// virtual
@@ -82,30 +71,6 @@ bool LLPanelSnapshotOptions::postBuild()
return LLPanel::postBuild();
}
-// virtual
-void LLPanelSnapshotOptions::onOpen(const LLSD& key)
-{
- updateUploadCost();
-}
-
-void LLPanelSnapshotOptions::updateUploadCost()
-{
- S32 w = 0;
- S32 h = 0;
-
- if( mSnapshotFloater )
- {
- LLSnapshotLivePreview* preview = mSnapshotFloater->getPreviewView();
- if( preview )
- {
- preview->getSize(w, h);
- }
- }
-
- S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(w, h);
- getChild<LLUICtrl>("save_to_inventory_btn")->setLabelArg("[AMOUNT]", llformat("%d", upload_cost));
-}
-
void LLPanelSnapshotOptions::openPanel(const std::string& panel_name)
{
LLSideTrayPanelContainer* parent = dynamic_cast<LLSideTrayPanelContainer*>(getParent());
diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp
index 23e8789e3f..3a17a1d58c 100644
--- a/indra/newview/llpanelsnapshotpostcard.cpp
+++ b/indra/newview/llpanelsnapshotpostcard.cpp
@@ -56,18 +56,18 @@ class LLPanelSnapshotPostcard
public:
LLPanelSnapshotPostcard();
- /*virtual*/ bool postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
+ bool postBuild() override;
+ void onOpen(const LLSD& key) override;
private:
- /*virtual*/ std::string getWidthSpinnerName() const { return "postcard_snapshot_width"; }
- /*virtual*/ std::string getHeightSpinnerName() const { return "postcard_snapshot_height"; }
- /*virtual*/ std::string getAspectRatioCBName() const { return "postcard_keep_aspect_check"; }
- /*virtual*/ std::string getImageSizeComboName() const { return "postcard_size_combo"; }
- /*virtual*/ std::string getImageSizePanelName() const { return "postcard_image_size_lp"; }
- /*virtual*/ LLSnapshotModel::ESnapshotFormat getImageFormat() const { return LLSnapshotModel::SNAPSHOT_FORMAT_JPEG; }
- /*virtual*/ LLSnapshotModel::ESnapshotType getSnapshotType();
- /*virtual*/ void updateControls(const LLSD& info);
+ std::string getWidthSpinnerName() const override { return "postcard_snapshot_width"; }
+ std::string getHeightSpinnerName() const override { return "postcard_snapshot_height"; }
+ std::string getAspectRatioCBName() const override { return "postcard_keep_aspect_check"; }
+ std::string getImageSizeComboName() const override { return "postcard_size_combo"; }
+ std::string getImageSizePanelName() const override { return "postcard_image_size_lp"; }
+ LLSnapshotModel::ESnapshotFormat getImageFormat() const override { return LLSnapshotModel::SNAPSHOT_FORMAT_JPEG; }
+ LLSnapshotModel::ESnapshotType getSnapshotType() override;
+ void updateControls(const LLSD& info) override;
bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response);
static void sendPostcardFinished(LLSD result);
@@ -86,8 +86,8 @@ static LLPanelInjector<LLPanelSnapshotPostcard> panel_class("llpanelsnapshotpost
LLPanelSnapshotPostcard::LLPanelSnapshotPostcard()
: mHasFirstMsgFocus(false)
{
- mCommitCallbackRegistrar.add("Postcard.Send", boost::bind(&LLPanelSnapshotPostcard::onSend, this));
- mCommitCallbackRegistrar.add("Postcard.Cancel", boost::bind(&LLPanelSnapshotPostcard::cancel, this));
+ mCommitCallbackRegistrar.add("Postcard.Send", { boost::bind(&LLPanelSnapshotPostcard::onSend, this), cb_info::UNTRUSTED_THROTTLE });
+ mCommitCallbackRegistrar.add("Postcard.Cancel", { boost::bind(&LLPanelSnapshotPostcard::cancel, this), cb_info::UNTRUSTED_THROTTLE });
}
diff --git a/indra/newview/llpanelsnapshotprofile.cpp b/indra/newview/llpanelsnapshotprofile.cpp
index aa257dea9e..960b507099 100644
--- a/indra/newview/llpanelsnapshotprofile.cpp
+++ b/indra/newview/llpanelsnapshotprofile.cpp
@@ -49,17 +49,17 @@ class LLPanelSnapshotProfile
public:
LLPanelSnapshotProfile();
- /*virtual*/ bool postBuild();
- /*virtual*/ void onOpen(const LLSD& key);
+ bool postBuild() override;
+ void onOpen(const LLSD& key) override;
private:
- /*virtual*/ std::string getWidthSpinnerName() const { return "profile_snapshot_width"; }
- /*virtual*/ std::string getHeightSpinnerName() const { return "profile_snapshot_height"; }
- /*virtual*/ std::string getAspectRatioCBName() const { return "profile_keep_aspect_check"; }
- /*virtual*/ std::string getImageSizeComboName() const { return "profile_size_combo"; }
- /*virtual*/ std::string getImageSizePanelName() const { return "profile_image_size_lp"; }
- /*virtual*/ LLSnapshotModel::ESnapshotFormat getImageFormat() const { return LLSnapshotModel::SNAPSHOT_FORMAT_PNG; }
- /*virtual*/ void updateControls(const LLSD& info);
+ std::string getWidthSpinnerName() const override { return "profile_snapshot_width"; }
+ std::string getHeightSpinnerName() const override { return "profile_snapshot_height"; }
+ std::string getAspectRatioCBName() const override { return "profile_keep_aspect_check"; }
+ std::string getImageSizeComboName() const override { return "profile_size_combo"; }
+ std::string getImageSizePanelName() const override { return "profile_image_size_lp"; }
+ LLSnapshotModel::ESnapshotFormat getImageFormat() const override { return LLSnapshotModel::SNAPSHOT_FORMAT_PNG; }
+ void updateControls(const LLSD& info) override;
void onSend();
};
@@ -68,8 +68,8 @@ static LLPanelInjector<LLPanelSnapshotProfile> panel_class("llpanelsnapshotprofi
LLPanelSnapshotProfile::LLPanelSnapshotProfile()
{
- mCommitCallbackRegistrar.add("PostToProfile.Send", boost::bind(&LLPanelSnapshotProfile::onSend, this));
- mCommitCallbackRegistrar.add("PostToProfile.Cancel", boost::bind(&LLPanelSnapshotProfile::cancel, this));
+ mCommitCallbackRegistrar.add("PostToProfile.Send", { boost::bind(&LLPanelSnapshotProfile::onSend, this), cb_info::UNTRUSTED_BLOCK });
+ mCommitCallbackRegistrar.add("PostToProfile.Cancel", { boost::bind(&LLPanelSnapshotProfile::cancel, this), cb_info::UNTRUSTED_BLOCK });
}
// virtual
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index 902412d359..8097e0ac0b 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -42,6 +42,7 @@
#include "llnotificationsutil.h"
#include "lltextbox.h"
#include "lltoggleablemenu.h"
+#include "llviewercontrol.h"
#include "llviewermenu.h"
#include "lllandmarkactions.h"
#include "llclipboard.h"
@@ -215,8 +216,18 @@ std::string LLTeleportHistoryFlatItem::getTimestamp()
// Only show timestamp for today and yesterday
if(time_diff < seconds_today + seconds_in_day)
{
- timestamp = "[" + LLTrans::getString("TimeHour12")+"]:["
- + LLTrans::getString("TimeMin")+"] ["+ LLTrans::getString("TimeAMPM")+"]";
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ if (use_24h)
+ {
+ timestamp = "[" + LLTrans::getString("TimeHour") + "]:["
+ + LLTrans::getString("TimeMin") + "]";
+ }
+ else
+ {
+ timestamp = "[" + LLTrans::getString("TimeHour12") + "]:["
+ + LLTrans::getString("TimeMin") + "] [" + LLTrans::getString("TimeAMPM") + "]";
+ }
+
LLSD substitution;
substitution["datetime"] = (S32) date.secondsSinceEpoch();
LLStringUtil::format(timestamp, substitution);
@@ -402,7 +413,7 @@ LLTeleportHistoryPanel::~LLTeleportHistoryPanel()
bool LLTeleportHistoryPanel::postBuild()
{
- mCommitCallbackRegistrar.add("TeleportHistory.GearMenu.Action", boost::bind(&LLTeleportHistoryPanel::onGearMenuAction, this, _2));
+ mCommitCallbackRegistrar.add("TeleportHistory.GearMenu.Action", { boost::bind(&LLTeleportHistoryPanel::onGearMenuAction, this, _2), cb_info::UNTRUSTED_THROTTLE });
mEnableCallbackRegistrar.add("TeleportHistory.GearMenu.Enable", boost::bind(&LLTeleportHistoryPanel::isActionEnabled, this, _2));
// init menus before list, since menus are passed to list
@@ -939,10 +950,9 @@ void LLTeleportHistoryPanel::onAccordionTabRightClick(LLView *view, S32 x, S32 y
// set up the callbacks for all of the avatar menu items
// (N.B. callbacks don't take const refs as mID is local scope)
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
-
- registrar.add("TeleportHistory.TabOpen", boost::bind(&LLTeleportHistoryPanel::onAccordionTabOpen, this, tab));
- registrar.add("TeleportHistory.TabClose", boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab));
+ ScopedRegistrarHelper registrar;
+ registrar.add("TeleportHistory.TabOpen", boost::bind(&LLTeleportHistoryPanel::onAccordionTabOpen, this, tab));
+ registrar.add("TeleportHistory.TabClose", boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab));
// create the context menu from the XUI
llassert(LLMenuGL::sMenuContainer != NULL);
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index e7ac11d570..d8a9de596d 100644
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -133,7 +133,7 @@ bool LLPanelTopInfoBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
if(!LLUICtrl::CommitCallbackRegistry::getValue("TopInfoBar.Action"))
{
LLUICtrl::CommitCallbackRegistry::currentRegistrar()
- .add("TopInfoBar.Action", boost::bind(&LLPanelTopInfoBar::onContextMenuItemClicked, this, _2));
+ .add("TopInfoBar.Action", { boost::bind(&LLPanelTopInfoBar::onContextMenuItemClicked, this, _2) });
}
show_topinfobar_context_menu(this, x, y);
return true;
diff --git a/indra/newview/llpanelvoicedevicesettings.cpp b/indra/newview/llpanelvoicedevicesettings.cpp
index 60877494e7..e65ba523f0 100644
--- a/indra/newview/llpanelvoicedevicesettings.cpp
+++ b/indra/newview/llpanelvoicedevicesettings.cpp
@@ -42,7 +42,7 @@
static LLPanelInjector<LLPanelVoiceDeviceSettings> t_panel_group_general("panel_voice_device_settings");
static const std::string DEFAULT_DEVICE("Default");
-
+static const std::string NO_DEVICE("No Device");
LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()
: LLPanel()
@@ -51,12 +51,10 @@ LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings()
mCtrlOutputDevices = NULL;
mInputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
mOutputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
- mDevicesUpdated = false; //obsolete
mUseTuningMode = true;
// grab "live" mic volume level
mMicVolume = gSavedSettings.getF32("AudioLevelMic");
-
}
LLPanelVoiceDeviceSettings::~LLPanelVoiceDeviceSettings()
@@ -81,7 +79,7 @@ bool LLPanelVoiceDeviceSettings::postBuild()
boost::bind(&LLPanelVoiceDeviceSettings::onCommitUnmute, this));
mLocalizedDeviceNames[DEFAULT_DEVICE] = getString("default_text");
- mLocalizedDeviceNames["No Device"] = getString("name_no_device");
+ mLocalizedDeviceNames[NO_DEVICE] = getString("name_no_device");
mLocalizedDeviceNames["Default System Device"] = getString("name_default_system_device");
mCtrlOutputDevices->setMouseDownCallback(boost::bind(&LLPanelVoiceDeviceSettings::onOutputDevicesClicked, this));
@@ -115,7 +113,7 @@ void LLPanelVoiceDeviceSettings::draw()
bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled();
if (voice_enabled)
{
- getChildView("wait_text")->setVisible( !is_in_tuning_mode && mUseTuningMode);
+ getChildView("wait_text")->setVisible(!is_in_tuning_mode && mUseTuningMode);
getChildView("disabled_text")->setVisible(false);
mUnmuteBtn->setVisible(false);
}
@@ -212,56 +210,29 @@ void LLPanelVoiceDeviceSettings::cancel()
void LLPanelVoiceDeviceSettings::refresh()
{
- //grab current volume
+ LLVoiceClient* voice_client = LLVoiceClient::getInstance();
+
+ // grab current volume
LLSlider* volume_slider = getChild<LLSlider>("mic_volume_slider");
+
// set mic volume tuning slider based on last mic volume setting
F32 current_volume = (F32)volume_slider->getValue().asReal();
- LLVoiceClient::getInstance()->tuningSetMicVolume(current_volume);
+ voice_client->tuningSetMicVolume(current_volume);
// Fill in popup menus
- bool device_settings_available = LLVoiceClient::getInstance()->deviceSettingsAvailable();
+ bool device_settings_available = voice_client->deviceSettingsAvailable();
+ bool device_settings_updated = voice_client->deviceSettingsUpdated();
if (mCtrlInputDevices)
{
- mCtrlInputDevices->setEnabled(device_settings_available);
- }
-
- if (mCtrlOutputDevices)
- {
- mCtrlOutputDevices->setEnabled(device_settings_available);
- }
-
- getChild<LLSlider>("mic_volume_slider")->setEnabled(device_settings_available);
-
- if(!device_settings_available)
- {
- // The combo boxes are disabled, since we can't get the device settings from the daemon just now.
- // Put the currently set default (ONLY) in the box, and select it.
- if(mCtrlInputDevices)
- {
- mCtrlInputDevices->removeall();
- mCtrlInputDevices->add(getLocalizedDeviceName(mInputDevice), mInputDevice, ADD_BOTTOM);
- mCtrlInputDevices->setValue(mInputDevice);
- }
- if(mCtrlOutputDevices)
- {
- mCtrlOutputDevices->removeall();
- mCtrlOutputDevices->add(getLocalizedDeviceName(mOutputDevice), mOutputDevice, ADD_BOTTOM);
- mCtrlOutputDevices->setValue(mOutputDevice);
- }
- }
- else if (LLVoiceClient::getInstance()->deviceSettingsUpdated())
- {
- LLVoiceDeviceList::const_iterator device;
-
- if(mCtrlInputDevices)
+ if (device_settings_available && !voice_client->getCaptureDevices().empty())
{
- LLVoiceDeviceList devices = LLVoiceClient::getInstance()->getCaptureDevices();
- if (devices.size() > 0) // if zero, we've not received our devices yet
+ mCtrlInputDevices->setEnabled(true);
+ if (device_settings_updated)
{
mCtrlInputDevices->removeall();
mCtrlInputDevices->add(getLocalizedDeviceName(DEFAULT_DEVICE), DEFAULT_DEVICE, ADD_BOTTOM);
- for (auto& device : devices)
+ for (auto& device : voice_client->getCaptureDevices())
{
mCtrlInputDevices->add(getLocalizedDeviceName(device.display_name), device.full_name, ADD_BOTTOM);
}
@@ -275,16 +246,24 @@ void LLPanelVoiceDeviceSettings::refresh()
}
}
}
+ else
+ {
+ mCtrlInputDevices->setEnabled(false);
+ mCtrlInputDevices->removeall();
+ mCtrlInputDevices->setLabel(getLocalizedDeviceName(NO_DEVICE));
+ }
+ }
- if(mCtrlOutputDevices)
+ if (mCtrlOutputDevices)
+ {
+ if (device_settings_available && !voice_client->getRenderDevices().empty())
{
- LLVoiceDeviceList devices = LLVoiceClient::getInstance()->getRenderDevices();
- if (devices.size() > 0) // if zero, we've not received our devices yet
+ mCtrlOutputDevices->setEnabled(true);
+ if (device_settings_updated)
{
mCtrlOutputDevices->removeall();
mCtrlOutputDevices->add(getLocalizedDeviceName(DEFAULT_DEVICE), DEFAULT_DEVICE, ADD_BOTTOM);
-
- for (auto& device : devices)
+ for (auto& device : voice_client->getRenderDevices())
{
mCtrlOutputDevices->add(getLocalizedDeviceName(device.display_name), device.full_name, ADD_BOTTOM);
}
@@ -298,7 +277,15 @@ void LLPanelVoiceDeviceSettings::refresh()
}
}
}
+ else
+ {
+ mCtrlOutputDevices->setEnabled(false);
+ mCtrlOutputDevices->removeall();
+ mCtrlOutputDevices->setLabel(getLocalizedDeviceName(NO_DEVICE));
+ }
}
+
+ getChild<LLSlider>("mic_volume_slider")->setEnabled(device_settings_available && !voice_client->getCaptureDevices().empty());
}
void LLPanelVoiceDeviceSettings::initialize()
diff --git a/indra/newview/llpanelvoicedevicesettings.h b/indra/newview/llpanelvoicedevicesettings.h
index 815396cbd1..d0d14c212c 100644
--- a/indra/newview/llpanelvoicedevicesettings.h
+++ b/indra/newview/llpanelvoicedevicesettings.h
@@ -63,7 +63,6 @@ protected:
class LLComboBox *mCtrlInputDevices;
class LLComboBox *mCtrlOutputDevices;
class LLButton *mUnmuteBtn;
- bool mDevicesUpdated;
bool mUseTuningMode;
std::map<std::string, std::string> mLocalizedDeviceNames;
};
diff --git a/indra/newview/llpanelvoiceeffect.cpp b/indra/newview/llpanelvoiceeffect.cpp
index a0129b2cb1..47f898e3ed 100644
--- a/indra/newview/llpanelvoiceeffect.cpp
+++ b/indra/newview/llpanelvoiceeffect.cpp
@@ -42,7 +42,7 @@ static LLPanelInjector<LLPanelVoiceEffect> t_panel_voice_effect("panel_voice_eff
LLPanelVoiceEffect::LLPanelVoiceEffect()
: mVoiceEffectCombo(NULL)
{
- mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this));
+ mCommitCallbackRegistrar.add("Voice.CommitVoiceEffect", { boost::bind(&LLPanelVoiceEffect::onCommitVoiceEffect, this), cb_info::UNTRUSTED_BLOCK });
}
LLPanelVoiceEffect::~LLPanelVoiceEffect()
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 951dc45a78..adbf2ebf6e 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -223,7 +223,7 @@ LLPanelVolume::LLPanelVolume()
{
setMouseOpaque(false);
- mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2));
+ mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", { boost::bind(&LLPanelVolume::menuDoToSelected, this, _2) });
mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2));
}
diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp
index 046bcd7f59..05b21d4d48 100644
--- a/indra/newview/llpanelvolumepulldown.cpp
+++ b/indra/newview/llpanelvolumepulldown.cpp
@@ -48,10 +48,10 @@
// Default constructor
LLPanelVolumePulldown::LLPanelVolumePulldown()
{
- mCommitCallbackRegistrar.add("Vol.setControlFalse", boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2));
- mCommitCallbackRegistrar.add("Vol.SetSounds", boost::bind(&LLPanelVolumePulldown::onClickSetSounds, this));
- mCommitCallbackRegistrar.add("Vol.updateCheckbox", boost::bind(&LLPanelVolumePulldown::updateCheckbox, this, _1, _2));
- mCommitCallbackRegistrar.add("Vol.GoAudioPrefs", boost::bind(&LLPanelVolumePulldown::onAdvancedButtonClick, this, _2));
+ mCommitCallbackRegistrar.add("Vol.setControlFalse", { boost::bind(&LLPanelVolumePulldown::setControlFalse, this, _2) });
+ mCommitCallbackRegistrar.add("Vol.SetSounds", { boost::bind(&LLPanelVolumePulldown::onClickSetSounds, this) });
+ mCommitCallbackRegistrar.add("Vol.updateCheckbox", { boost::bind(&LLPanelVolumePulldown::updateCheckbox, this, _1, _2) });
+ mCommitCallbackRegistrar.add("Vol.GoAudioPrefs", { boost::bind(&LLPanelVolumePulldown::onAdvancedButtonClick, this, _2) });
buildFromFile( "panel_volume_pulldown.xml");
}
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index c1534c9abd..b4f6db9287 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -62,7 +62,7 @@ public:
LLWearingGearMenu(LLPanelWearing* panel_wearing)
: mMenu(NULL), mPanelWearing(panel_wearing)
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
registrar.add("Gear.TouchAttach", boost::bind(&LLWearingGearMenu::handleMultiple, this, handle_attachment_touch));
@@ -103,7 +103,7 @@ class LLWearingContextMenu : public LLListContextMenu
protected:
/* virtual */ LLContextMenu* createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
registrar.add("Wearing.TouchAttach", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs));
registrar.add("Wearing.EditItem", boost::bind(handleMultiple, handle_item_edit, mUUIDs));
@@ -113,6 +113,7 @@ protected:
boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op));
registrar.add("Wearing.Detach",
boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op));
+ registrar.add("Wearing.Favorite", boost::bind(toggle_favorites, mUUIDs));
LLContextMenu* menu = createFromFile("menu_wearing_tab.xml");
updateMenuItemsVisibility(menu);
@@ -125,6 +126,8 @@ protected:
bool bp_selected = false; // true if body parts selected
bool clothes_selected = false;
bool attachments_selected = false;
+ bool can_favorite = false;
+ bool can_unfavorite = false;
// See what types of wearables are selected.
for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it)
@@ -137,6 +140,9 @@ protected:
continue;
}
+ LLUUID linked_id = item->getLinkedUUID();
+ LLViewerInventoryItem* linked_item = gInventory.getItem(linked_id);
+
LLAssetType::EType type = item->getType();
if (type == LLAssetType::AT_CLOTHING)
{
@@ -150,6 +156,8 @@ protected:
{
attachments_selected = true;
}
+ can_favorite |= !linked_item->getIsFavorite();
+ can_unfavorite |= linked_item->getIsFavorite();
}
// Enable/disable some menu items depending on the selection.
@@ -162,10 +170,12 @@ protected:
menu->setItemEnabled("touch_attach", 1 == mUUIDs.size() && enable_attachment_touch(mUUIDs.front()));
menu->setItemVisible("edit_item", show_edit);
menu->setItemEnabled("edit_item", 1 == mUUIDs.size() && get_is_item_editable(mUUIDs.front()));
- menu->setItemVisible("take_off", allow_take_off);
- menu->setItemVisible("detach", allow_detach);
+ menu->setItemVisible("take_off", allow_take_off);
+ menu->setItemVisible("detach", allow_detach);
menu->setItemVisible("edit_outfit_separator", show_touch | show_edit | allow_take_off || allow_detach);
- menu->setItemVisible("show_original", mUUIDs.size() == 1);
+ menu->setItemVisible("show_original", mUUIDs.size() == 1);
+ menu->setItemVisible("favorites_add", can_favorite);
+ menu->setItemVisible("favorites_remove", can_unfavorite);
}
};
@@ -180,7 +190,7 @@ public:
protected:
/* virtual */ LLContextMenu* createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
registrar.add("Wearing.EditItem", boost::bind(&LLPanelWearing::onEditAttachment, mPanelWearing));
registrar.add("Wearing.Detach", boost::bind(&LLPanelWearing::onRemoveAttachment, mPanelWearing));
@@ -232,6 +242,10 @@ LLPanelWearing::~LLPanelWearing()
{
mAttachmentsChangedConnection.disconnect();
}
+ if (mGearMenuConnection.connected())
+ {
+ mGearMenuConnection.disconnect();
+ }
}
bool LLPanelWearing::postBuild()
@@ -249,10 +263,6 @@ bool LLPanelWearing::postBuild()
mTempItemsList->setFgUnselectedColor(LLColor4::white);
mTempItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onTempAttachmentsListRightClick, this, _1, _2, _3));
- LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
-
- menu_gear_btn->setMenu(mGearMenu->getMenu());
-
return true;
}
@@ -560,6 +570,16 @@ void LLPanelWearing::onRemoveAttachment()
}
}
+LLToggleableMenu* LLPanelWearing::getGearMenu()
+{
+ return mGearMenu->getMenu();
+}
+
+LLToggleableMenu* LLPanelWearing::getSortMenu()
+{
+ return NULL;
+}
+
void LLPanelWearing::onRemoveItem()
{
if (mWearablesTab->isExpanded())
diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h
index ea0787d0ef..aa80a3fc21 100644
--- a/indra/newview/llpanelwearing.h
+++ b/indra/newview/llpanelwearing.h
@@ -84,6 +84,11 @@ public:
void onEditAttachment();
void onRemoveAttachment();
+ void updateMenuItemsVisibility() {};
+ LLToggleableMenu* getGearMenu();
+ LLToggleableMenu* getSortMenu();
+ bool getTrashMenuVisible() { return false; }
+
private:
void onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
void onTempAttachmentsListRightClick(LLUICtrl* ctrl, S32 x, S32 y);
@@ -93,6 +98,7 @@ private:
LLWearableItemsList* mCOFItemsList;
LLScrollListCtrl* mTempItemsList;
LLWearingGearMenu* mGearMenu;
+ boost::signals2::connection mGearMenuConnection;
LLListContextMenu* mContextMenu;
LLListContextMenu* mAttachmentsMenu;
diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp
index 7d11c09738..01a3902516 100644
--- a/indra/newview/llpreviewanim.cpp
+++ b/indra/newview/llpreviewanim.cpp
@@ -46,7 +46,7 @@ const S32 ADVANCED_VPAD = 3;
LLPreviewAnim::LLPreviewAnim(const LLSD& key)
: LLPreview( key )
{
- mCommitCallbackRegistrar.add("PreviewAnim.Play", boost::bind(&LLPreviewAnim::play, this, _2));
+ mCommitCallbackRegistrar.add("PreviewAnim.Play", { boost::bind(&LLPreviewAnim::play, this, _2) });
}
// virtual
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 02a4c7fb26..6292cc7810 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -503,7 +503,7 @@ bool LLScriptEdCore::postBuild()
LLSyntaxIdLSL::getInstance()->initialize();
processKeywords();
- mCommitCallbackRegistrar.add("FontSize.Set", boost::bind(&LLScriptEdCore::onChangeFontSize, this, _2));
+ mCommitCallbackRegistrar.add("FontSize.Set", { boost::bind(&LLScriptEdCore::onChangeFontSize, this, _2) });
mEnableCallbackRegistrar.add("FontSize.Check", boost::bind(&LLScriptEdCore::isFontSizeChecked, this, _2));
LLToggleableMenu *context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
@@ -703,9 +703,10 @@ void LLScriptEdCore::sync()
}
}
-bool LLScriptEdCore::hasChanged()
+bool LLScriptEdCore::hasChanged() const
{
- if (!mEditor) return false;
+ if (!mEditor)
+ return false;
return ((!mEditor->isPristine() || mEnableSave) && mHasScriptData);
}
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index 70ee1a4274..0bbe540207 100644
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -143,7 +143,7 @@ public:
void setItemRemoved(bool script_removed){mScriptRemoved = script_removed;};
void setAssetID( const LLUUID& asset_id){ mAssetID = asset_id; };
- LLUUID getAssetID() { return mAssetID; }
+ LLUUID getAssetID() const { return mAssetID; }
bool isFontSizeChecked(const LLSD &userdata);
void onChangeFontSize(const LLSD &size_name);
@@ -155,7 +155,7 @@ public:
void onBtnDynamicHelp();
void onBtnUndoChanges();
- bool hasChanged();
+ bool hasChanged() const;
void selectFirstError();
@@ -211,7 +211,6 @@ class LLScriptEdContainer : public LLPreview
public:
LLScriptEdContainer(const LLSD& key);
- LLScriptEdContainer(const LLSD& key, const bool live);
bool handleKeyHere(KEY key, MASK mask);
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index f77d37f821..07e2c39379 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -256,7 +256,7 @@ bool LLReflectionMap::getBox(LLMatrix4& box)
glm::mat4 mv(get_current_modelview());
LLVector3 s = mViewerObject->getScale().scaledVec(LLVector3(0.5f, 0.5f, 0.5f));
mRadius = s.magVec();
- glm::mat4 scale = glm::scale(glm::make_vec3(s.mV));
+ glm::mat4 scale = glm::scale(glm::make_vec3(LLVector4(s).mV));
if (mViewerObject->mDrawable != nullptr)
{
// object to agent space (no scale)
diff --git a/indra/newview/llsaveoutfitcombobtn.cpp b/indra/newview/llsaveoutfitcombobtn.cpp
index 6418c310c1..bc1bdfdcda 100644
--- a/indra/newview/llsaveoutfitcombobtn.cpp
+++ b/indra/newview/llsaveoutfitcombobtn.cpp
@@ -39,7 +39,7 @@ LLSaveOutfitComboBtn::LLSaveOutfitComboBtn(LLPanel* parent, bool saveAsDefaultAc
mParent(parent), mSaveAsDefaultAction(saveAsDefaultAction)
{
// register action mapping before creating menu
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar;
+ LLUICtrl::ScopedRegistrarHelper save_registar;
save_registar.add("Outfit.Save.Action", boost::bind(
&LLSaveOutfitComboBtn::saveOutfit, this, false));
save_registar.add("Outfit.SaveAs.Action", boost::bind(
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index 14dda20225..73920d35ad 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -312,7 +312,7 @@ public:
mIdentifier = identifier;
mAuthenticator = authenticator;
}
- virtual LLSD getIdentifier() { return mIdentifier; }
+ virtual LLSD getIdentifier() const { return mIdentifier; }
virtual void identifierType(std::string& idType);
virtual LLSD getAuthenticator() { return mAuthenticator; }
virtual void authenticatorType(std::string& authType);
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 8a3c8b9b17..6d0dac41db 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -243,6 +243,23 @@ LLSelectMgr::LLSelectMgr()
mForceSelection = false;
mShowSelection = false;
+
+ LLControlVariable* ctrl = gSavedSettings.getControl("DebugSelectionLODs").get();
+ if (ctrl)
+ {
+ mSlectionLodModChangedConnection = ctrl->getSignal()->connect([this](LLControlVariable*, const LLSD&, const LLSD&)
+ {
+ for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
+ iter != mSelectedObjects->end(); ++iter)
+ {
+ LLViewerObject* object = (*iter)->getObject();
+ if (object)
+ {
+ object->updateLOD();
+ }
+ }
+ });
+ }
}
@@ -252,6 +269,7 @@ LLSelectMgr::LLSelectMgr()
LLSelectMgr::~LLSelectMgr()
{
clearSelections();
+ mSlectionLodModChangedConnection.disconnect();
}
void LLSelectMgr::clearSelections()
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index f8242675dc..40e4891bd9 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -938,6 +938,7 @@ private:
bool mForceSelection;
std::vector<LLAnimPauseRequest> mPauseRequests;
+ boost::signals2::connection mSlectionLodModChangedConnection;
};
// *DEPRECATED: For callbacks or observers, use
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp
index 5dbd579b45..021a9feb73 100644
--- a/indra/newview/llsetkeybinddialog.cpp
+++ b/indra/newview/llsetkeybinddialog.cpp
@@ -46,14 +46,12 @@ public:
:LLEventTimer(period),
mMask(mask),
mCallback(cb)
- {
- mEventTimer.start();
- }
+ {}
virtual ~Updater(){}
protected:
- bool tick()
+ bool tick() override
{
mCallback(mMask);
// Deletes itseft after execution
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index c618483fc4..1d1b31d2a6 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -40,6 +40,7 @@
#include "llfloaterworldmap.h"
#include "llfolderviewmodel.h"
#include "llloadingindicator.h"
+#include "llmenubutton.h"
#include "lloutfitobserver.h"
#include "llpaneleditwearable.h"
#include "llpaneloutfitsinventory.h"
@@ -145,6 +146,14 @@ bool LLSidepanelAppearance::postBuild()
setWearablesLoading(gAgentWearables.isCOFChangeInProgress());
+
+ LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
+ LLMenuButton* menu_sort_btn = getChild<LLMenuButton>("sorting_menu_btn");
+ LLButton* menu_trash_btn = getChild<LLButton>("trash_btn");
+ LLPanel* menu_sort_btn_panel = getChild<LLPanel>("options_sort_btn_panel");
+ LLPanel* menu_trash_btn_panel = getChild<LLPanel>("trash_btn_panel");
+ mPanelOutfitsInventory->setMenuButtons(menu_gear_btn, menu_sort_btn, menu_trash_btn, menu_sort_btn_panel, menu_trash_btn_panel);
+
return true;
}
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index fccf745a74..8998d61c47 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -56,6 +56,8 @@
#include "llviewerregion.h"
+const char* const DEFAULT_DESC = "(No Description)";
+
class PropertiesChangedCallback : public LLInventoryCallback
{
public:
@@ -128,6 +130,7 @@ LLSidepanelItemInfo::LLSidepanelItemInfo(const LLPanel::Params& p)
, mUpdatePendingId(-1)
, mIsDirty(false) /*Not ready*/
, mParentFloater(NULL)
+ , mLabelItemDesc(NULL)
{
gInventory.addObserver(this);
gIdleCallbacks.addFunction(&LLSidepanelItemInfo::onIdle, (void*)this);
@@ -158,10 +161,11 @@ bool LLSidepanelItemInfo::postBuild()
mItemTypeIcon = getChild<LLIconCtrl>("item_type_icon");
mLabelOwnerName = getChild<LLTextBox>("LabelOwnerName");
mLabelCreatorName = getChild<LLTextBox>("LabelCreatorName");
+ mLabelItemDesc = getChild<LLTextEditor>("LabelItemDesc");
getChild<LLLineEditor>("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
getChild<LLUICtrl>("LabelItemName")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitName,this));
- getChild<LLUICtrl>("LabelItemDesc")->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this));
+ mLabelItemDesc->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this));
// Thumnail edition
mChangeThumbnailBtn->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onEditThumbnail, this));
// acquired date
@@ -342,10 +346,14 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
getChildView("LabelItemName")->setEnabled(is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards
getChild<LLUICtrl>("LabelItemName")->setValue(item->getName());
getChildView("LabelItemDescTitle")->setEnabled(true);
- getChildView("LabelItemDesc")->setEnabled(is_modifiable);
- getChild<LLUICtrl>("LabelItemDesc")->setValue(item->getDescription());
getChild<LLUICtrl>("item_thumbnail")->setValue(item->getThumbnailUUID());
+ // Asset upload substitutes empty description with a (No Description) placeholder
+ std::string desc = item->getDescription();
+ mLabelItemDesc->setSelectAllOnFocusReceived(desc == DEFAULT_DESC);
+ mLabelItemDesc->setValue(desc);
+ mLabelItemDesc->setEnabled(is_modifiable);
+
LLUIImagePtr icon_img = LLInventoryIcon::getIcon(item->getType(), item->getInventoryType(), item->getFlags(), false);
mItemTypeIcon->setImage(icon_img);
@@ -483,7 +491,8 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
}
else
{
- std::string timeStr = getString("acquiredDate");
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ std::string timeStr = use_24h ? getString("acquiredDate") : getString("acquiredDateAMPM");
LLSD substitution;
substitution["datetime"] = (S32) time_utc;
LLStringUtil::format (timeStr, substitution);
@@ -923,17 +932,22 @@ void LLSidepanelItemInfo::onCommitDescription()
LLViewerInventoryItem* item = findItem();
if(!item) return;
- LLTextEditor* labelItemDesc = getChild<LLTextEditor>("LabelItemDesc");
- if(!labelItemDesc)
+ if(!mLabelItemDesc)
+ {
+ return;
+ }
+ if (!gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE))
{
return;
}
- if((item->getDescription() != labelItemDesc->getText()) &&
- (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)))
+ std::string old_desc = item->getDescription();
+ std::string new_desc = mLabelItemDesc->getText();
+ if(old_desc != new_desc)
{
+ mLabelItemDesc->setSelectAllOnFocusReceived(false);
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->setDescription(labelItemDesc->getText());
+ new_item->setDescription(new_desc);
onCommitChanges(new_item);
}
}
diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h
index 718edc79d6..0895d3360c 100644
--- a/indra/newview/llsidepaneliteminfo.h
+++ b/indra/newview/llsidepaneliteminfo.h
@@ -46,6 +46,7 @@ class LLObjectInventoryObserver;
class LLViewerObject;
class LLPermissions;
class LLTextBox;
+class LLTextEditor;
class LLSidepanelItemInfo : public LLPanel, public LLInventoryObserver
{
@@ -105,6 +106,7 @@ private:
LLIconCtrl* mItemTypeIcon;
LLTextBox* mLabelOwnerName;
LLTextBox* mLabelCreatorName;
+ LLTextEditor* mLabelItemDesc;
//
// UI Elements
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index cee43f3cff..afa4686d52 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -116,8 +116,8 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin
// needed for handling of any legacy bad data.
if (!avatar->getJoint(skin->mJointNames[j]))
{
- LL_DEBUGS("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL;
- LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL;
+ LL_DEBUGS("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL;
+ LL_WARNS_ONCE("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL;
skin->mJointNames[j] = "mPelvis";
skin->mJointNumsInitialized = false; // force update after names change.
}
diff --git a/indra/newview/llsky.cpp b/indra/newview/llsky.cpp
index 82caa14433..66fbe0029a 100644
--- a/indra/newview/llsky.cpp
+++ b/indra/newview/llsky.cpp
@@ -39,7 +39,7 @@
// linden library includes
#include "llerror.h"
#include "llmath.h"
-#include "math.h"
+#include <cmath>
#include "v4color.h"
#include "llviewerobjectlist.h"
diff --git a/indra/newview/llsky.h b/indra/newview/llsky.h
index 32599dcee2..d06f181357 100644
--- a/indra/newview/llsky.h
+++ b/indra/newview/llsky.h
@@ -28,7 +28,6 @@
#define LL_LLSKY_H
#include "llmath.h"
-//#include "vmath.h"
#include "v3math.h"
#include "v4math.h"
#include "v4color.h"
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index ea95d71b27..7d5f380886 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -1066,7 +1066,7 @@ void LLSnapshotLivePreview::saveTexture(bool outfit_snapshot, std::string name)
tid, LLAssetType::AT_TEXTURE, res_name, res_desc, 0,
folder_type, inv_type,
PERM_ALL, LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"),
- expected_upload_cost, !outfit_snapshot));
+ expected_upload_cost, LLUUID::null, !outfit_snapshot));
upload_new_resource(assetUploadInfo);
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index ad2461f60f..077a949c05 100644
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -37,7 +37,7 @@ class LLSpeakerMgr;
class LLAvatarName;
// data for a given participant in a voice channel
-class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable
+class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>
{
public:
typedef enum e_speaker_type
@@ -159,7 +159,7 @@ public:
*
* If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass().
*/
- virtual bool tick();
+ bool tick() override;
/**
* Clears the callback.
diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp
index e51aeb6080..09c57eaf1d 100644
--- a/indra/newview/llsprite.cpp
+++ b/indra/newview/llsprite.cpp
@@ -37,7 +37,7 @@
#include "llsprite.h"
-#include "math.h"
+#include <cmath>
#include "lldrawable.h"
#include "llface.h"
diff --git a/indra/newview/llsprite.h b/indra/newview/llsprite.h
index 44439bd30c..d6e8e37ec9 100644
--- a/indra/newview/llsprite.h
+++ b/indra/newview/llsprite.h
@@ -27,8 +27,6 @@
#ifndef LL_LLSPRITE_H
#define LL_LLSPRITE_H
-////#include "vmath.h"
-//#include "llmath.h"
#include "v3math.h"
#include "v4math.h"
#include "v4color.h"
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 9b715be26e..3a831f5186 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -185,7 +185,6 @@
#include "llnamelistctrl.h"
#include "llnamebox.h"
#include "llnameeditor.h"
-#include "llpostprocess.h"
#include "llagentlanguage.h"
#include "llwearable.h"
#include "llinventorybridge.h"
@@ -209,6 +208,7 @@
#include "threadpool.h"
#include "llperfstats.h"
+#include "rlvhandler.h"
#if LL_WINDOWS
#include "lldxhardware.h"
@@ -410,10 +410,10 @@ bool idle_startup()
static bool first_call = true;
if (first_call)
{
+ first_call = false;
// Other phases get handled when startup state changes,
// need to capture the initial state as well.
LLStartUp::getPhases().startPhase(LLStartUp::getStartupStateString());
- first_call = false;
}
gViewerWindow->showCursor();
@@ -903,6 +903,8 @@ bool idle_startup()
return false;
}
+ RlvHandler::setEnabled(gSavedSettings.get<bool>(Rlv::Settings::Main));
+
// reset the values that could have come in from a slurl
// DEV-42215: Make sure they're not empty -- gUserCredential
// might already have been set from gSavedSettings, and it's too bad
@@ -1319,10 +1321,6 @@ bool idle_startup()
LLDrawable::initClass();
display_startup();
- // init the shader managers
- LLPostProcess::initClass();
- display_startup();
-
LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml");
display_startup();
diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h
index 10a104730b..fc72ab7db7 100644
--- a/indra/newview/llsurface.h
+++ b/indra/newview/llsurface.h
@@ -27,7 +27,6 @@
#ifndef LL_LLSURFACE_H
#define LL_LLSURFACE_H
-//#include "vmath.h"
#include "v3math.h"
#include "v3dmath.h"
#include "v4math.h"
diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp
index dd7c6aa9e3..e02f76711c 100644
--- a/indra/newview/llteleporthistorystorage.cpp
+++ b/indra/newview/llteleporthistorystorage.cpp
@@ -127,6 +127,12 @@ void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d
S32 removed_index = -1;
if (item_iter != mItems.end())
{
+ // When teleporting via history it's possible that there can be
+ // an offset applied to the position, so each new teleport can
+ // be a meter higher than the last.
+ // Avoid it by preserving original position.
+ item.mGlobalPos = item_iter->mGlobalPos;
+
removed_index = (S32)(item_iter - mItems.begin());
mItems.erase(item_iter);
}
diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp
index 8ccde74c93..a858f92d8e 100644
--- a/indra/newview/llterrainpaintmap.cpp
+++ b/indra/newview/llterrainpaintmap.cpp
@@ -31,6 +31,8 @@
// library includes
#include "llglslshader.h"
#include "llrendertarget.h"
+#include "llrender2dutils.h"
+#include "llshadermgr.h"
#include "llvertexbuffer.h"
// newview includes
@@ -38,18 +40,31 @@
#include "llsurface.h"
#include "llsurfacepatch.h"
#include "llviewercamera.h"
+#include "llviewercontrol.h"
#include "llviewerregion.h"
#include "llviewershadermgr.h"
#include "llviewertexture.h"
-// static
-bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex)
+namespace
+{
+#ifdef SHOW_ASSERT
+void check_tex(const LLViewerTexture& tex)
{
llassert(tex.getComponents() == 3);
llassert(tex.getWidth() > 0 && tex.getHeight() > 0);
llassert(tex.getWidth() == tex.getHeight());
llassert(tex.getPrimaryFormat() == GL_RGB);
llassert(tex.getGLTexture());
+}
+#else
+#define check_tex(tex)
+#endif
+} // namespace
+
+// static
+bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex)
+{
+ check_tex(tex);
const LLSurface& surface = region.getLand();
const U32 patch_count = surface.getPatchesPerEdge();
@@ -76,8 +91,8 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&
// Bind the debug shader and render terrain to tex
// Use a scratch render target because its dimensions may exceed the standard bake target, and this is a one-off bake
LLRenderTarget scratch_target;
- const S32 dim = llmin(tex.getWidth(), tex.getHeight());
- scratch_target.allocate(dim, dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE,
+ const S32 max_dim = llmax(tex.getWidth(), tex.getHeight());
+ scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE,
LLTexUnit::eTextureMipGeneration::TMG_NONE);
if (!scratch_target.isComplete())
{
@@ -104,6 +119,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&
const F32 region_half_width = region_width / 2.0f;
const F32 region_camera_height = surface.getMaxZ() + DEFAULT_NEAR_PLANE;
LLViewerCamera camera;
+ // TODO: Huh... I just realized this view vector is not completely vertical
const LLVector3 region_center = LLVector3(region_half_width, region_half_width, 0.0) + region.getOriginAgent();
const LLVector3 camera_origin = LLVector3(0.0f, 0.0f, region_camera_height) + region_center;
camera.lookAt(camera_origin, region_center, LLVector3::y_axis);
@@ -237,6 +253,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&
S32 alpha_ramp = shader.enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
LLPointer<LLViewerTexture> alpha_ramp_texture = LLViewerTextureManager::getFetchedTexture(IMG_ALPHA_GRAD_2D);
+ // TODO: Consider using LLGLSLShader::bindTexture
gGL.getTexUnit(alpha_ramp)->bind(alpha_ramp_texture);
gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
@@ -250,6 +267,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&
const U32 vertex_offset = n * patch_index;
llassert(index_offset + ni <= region_indices);
llassert(vertex_offset + n <= region_vertices);
+ // TODO: Try a single big drawRange and see if that still works
buf->drawRange(LLRender::TRIANGLES, vertex_offset, vertex_offset + n - 1, ni, index_offset);
}
}
@@ -269,7 +287,7 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&
gGL.flush();
LLVertexBuffer::unbind();
// Final step: Copy the output to the terrain paintmap
- const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, dim, dim);
+ const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, tex.getWidth(), tex.getHeight());
if (!success)
{
LL_WARNS() << "Failed to copy framebuffer to paintmap" << LL_ENDL;
@@ -283,3 +301,687 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&
return success;
}
+
+// *TODO: Decide when to apply the paint queue - ideally once per frame per region
+// Applies paints and then clears the paint queue
+// *NOTE The paint queue is also cleared when setting the paintmap texture
+void LLTerrainPaintMap::applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue)
+{
+ if (queue.empty()) { return; }
+
+ check_tex(tex);
+
+ gGL.getTexUnit(0)->bind(tex.getGLTexture(), false, true);
+
+ // glTexSubImage2D replaces all pixels in the rectangular region. That
+ // makes it unsuitable for alpha.
+ llassert(queue.getComponents() == LLTerrainPaint::RGB);
+ constexpr GLenum pixformat = GL_RGB;
+
+ const std::vector<LLTerrainPaint::ptr_t>& queue_list = queue.get();
+ for (size_t i = 0; i < queue_list.size(); ++i)
+ {
+ // It is currently the responsibility of the paint queue to convert
+ // incoming bits to the right bit depth for the paintmap (this could
+ // change in the future).
+ queue.convertBitDepths(i, 8);
+ const LLTerrainPaint::ptr_t& paint = queue_list[i];
+
+ if (paint->mData.empty()) { continue; }
+ constexpr GLint level = 0;
+ if ((paint->mStartX >= tex.getWidth() - 1) || (paint->mStartY >= tex.getHeight() - 1)) { continue; }
+ constexpr GLint miplevel = 0;
+ const S32 x_offset = paint->mStartX;
+ const S32 y_offset = paint->mStartY;
+ const S32 width = llmin(paint->mWidthX, tex.getWidth() - x_offset);
+ const S32 height = llmin(paint->mWidthY, tex.getHeight() - y_offset);
+ const U8* pixels = paint->mData.data();
+ constexpr GLenum pixtype = GL_UNSIGNED_BYTE;
+ // *TODO: Performance suggestion: Use the sub-image utility function
+ // that LLImageGL::setSubImage uses to split texture updates into
+ // lines, if that's faster.
+ glTexSubImage2D(GL_TEXTURE_2D, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, pixels);
+ stop_glerror();
+ }
+
+ // Generating mipmaps at the end...
+ glGenerateMipmap(GL_TEXTURE_2D);
+ stop_glerror();
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ queue.clear();
+}
+
+namespace
+{
+
+// A general-purpose vertex buffer of a quad for stamping textures on the z=0
+// plane.
+// *NOTE: Because we know the vertex XY coordinates go from 0 to 1
+// pre-transform, UVs can be calculated from the vertices
+LLVertexBuffer* get_paint_triangle_buffer()
+{
+ static LLPointer<LLVertexBuffer> buf = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX);
+ static bool initialized = false;
+ if (!initialized)
+ {
+ // Two triangles forming a square from (0,0) to (1,1)
+ buf->allocateBuffer(/*vertices =*/ 4, /*indices =*/ 6);
+ LLStrider<U16> indices;
+ LLStrider<LLVector3> vertices;
+ buf->getVertexStrider(vertices);
+ buf->getIndexStrider(indices);
+ // y
+ // 2....3
+ // ^ . .
+ // | 0....1
+ // |
+ // -------> x
+ //
+ // triangle 1: 0,1,2
+ // triangle 2: 1,3,2
+ (*(vertices++)).set(0.0f, 0.0f, 0.0f);
+ (*(vertices++)).set(1.0f, 0.0f, 0.0f);
+ (*(vertices++)).set(0.0f, 1.0f, 0.0f);
+ (*(vertices++)).set(1.0f, 1.0f, 0.0f);
+ *(indices++) = 0;
+ *(indices++) = 1;
+ *(indices++) = 2;
+ *(indices++) = 1;
+ *(indices++) = 3;
+ *(indices++) = 2;
+ buf->unmapBuffer();
+ }
+ return buf.get();
+}
+
+};
+
+// static
+LLTerrainPaintQueue LLTerrainPaintMap::convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in)
+{
+ check_tex(tex);
+ llassert(queue_in.getComponents() == LLTerrainPaint::RGBA);
+
+ // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead
+ // TODO: even if it means performing extra render operations to apply the paints, in rare cases where the paints can't all fit within an area that can be represented by the buffer
+ LLRenderTarget scratch_target;
+ const S32 max_dim = llmax(tex.getWidth(), tex.getHeight());
+ scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE,
+ LLTexUnit::eTextureMipGeneration::TMG_NONE);
+ if (!scratch_target.isComplete())
+ {
+ llassert(false);
+ LL_WARNS() << "Failed to allocate render target" << LL_ENDL;
+ return false;
+ }
+ gGL.getTexUnit(0)->disable();
+ stop_glerror();
+
+ scratch_target.bindTarget();
+ glClearColor(0, 0, 0, 0);
+ scratch_target.clear();
+ const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f;
+ const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f;
+
+ LLVertexBuffer* buf = get_paint_triangle_buffer();
+
+ // Update projection matrix and viewport
+ // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later.
+ {
+ stop_glerror();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.ortho(-target_half_width, target_half_width, -target_half_height, target_half_height, 0.25f, 1.0f);
+ stop_glerror();
+ const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0);
+ glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight());
+ }
+
+ // View matrix
+ // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer.
+ // Camera is centered in the middle of the framebuffer.
+ glm::mat4 view(glm::make_mat4((GLfloat*) OGL_TO_CFR_ROTATION));
+ {
+ LLViewerCamera camera;
+ const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f);
+ const LLVector3 camera_look_down(target_half_width, target_half_height, 0.0f);
+ camera.lookAt(camera_origin, camera_look_down, LLVector3::y_axis);
+ camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth()));
+ GLfloat ogl_matrix[16];
+ camera.getOpenGLTransform(ogl_matrix);
+ view *= glm::make_mat4(ogl_matrix);
+ }
+
+ LLGLDisable stencil(GL_STENCIL_TEST);
+ LLGLDisable scissor(GL_SCISSOR_TEST);
+ LLGLEnable cull_face(GL_CULL_FACE);
+ LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS);
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ LLGLSLShader& shader = gTerrainStampProgram;
+ shader.bind();
+
+ // First, apply the paint map as the background
+ {
+ glm::mat4 model;
+ {
+ model = glm::scale(model, glm::vec3((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f));
+ model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
+ }
+ glm::mat4 modelview = view * model;
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.loadMatrix(glm::value_ptr(modelview));
+
+ shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex);
+ // We care about the whole paintmap, which is already a power of two.
+ // Hence, TERRAIN_STAMP_SCALE = (1.0,1.0)
+ shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f);
+ buf->setBuffer();
+ buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0);
+ }
+
+ LLTerrainPaintQueue queue_out(LLTerrainPaint::RGB);
+
+ // Incrementally apply each RGBA paint to the render target, then extract
+ // the result back into memory as an RGB paint.
+ // Put each result in queue_out.
+ const std::vector<LLTerrainPaint::ptr_t>& queue_in_list = queue_in.get();
+ for (size_t i = 0; i < queue_in_list.size(); ++i)
+ {
+ // It is currently the responsibility of the paint queue to convert
+ // incoming bits to the right bit depth for paint operations (this
+ // could change in the future).
+ queue_in.convertBitDepths(i, 8);
+ const LLTerrainPaint::ptr_t& paint_in = queue_in_list[i];
+
+ // Modelview matrix for the current paint
+ // View matrix is already computed. Just need the model matrix.
+ // Orthographic projection matrix is already updated
+ glm::mat4 model;
+ {
+ model = glm::scale(model, glm::vec3(paint_in->mWidthX, paint_in->mWidthY, 1.0f));
+ model = glm::translate(model, glm::vec3(paint_in->mStartX, paint_in->mStartY, 0.0f));
+ }
+ glm::mat4 modelview = view * model;
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.loadMatrix(glm::value_ptr(modelview));
+
+ // Generate temporary stamp texture from paint contents.
+ // Our stamp image needs to be a power of two.
+ // Because the paint data may not cover a whole power-of-two region,
+ // allocate a bigger 2x2 image if needed, but set the image data later
+ // for a subset of the image.
+ // Pixel data outside this subset is left undefined. We will use
+ // TERRAIN_STAMP_SCALE in the stamp shader to define the subset of the
+ // image we care about.
+ const U32 width_rounded = 1 << U32(ceil(log2(F32(paint_in->mWidthX))));
+ const U32 height_rounded = 1 << U32(ceil(log2(F32(paint_in->mWidthY))));
+ LLPointer<LLImageGL> stamp_image;
+ {
+ // Create image object (dimensions not yet initialized in GL)
+ U32 stamp_tex_name;
+ LLImageGL::generateTextures(1, &stamp_tex_name);
+ const U32 components = paint_in->mComponents;
+ constexpr LLGLenum target = GL_TEXTURE_2D;
+ const LLGLenum internal_format = paint_in->mComponents == 4 ? GL_RGBA8 : GL_RGB8;
+ const LLGLenum format = paint_in->mComponents == 4 ? GL_RGBA : GL_RGB;
+ constexpr LLGLenum type = GL_UNSIGNED_BYTE;
+ stamp_image = new LLImageGL(stamp_tex_name, components, target, internal_format, format, type, LLTexUnit::TAM_WRAP);
+ // Nearest-neighbor filtering to reduce surprises
+ stamp_image->setFilteringOption(LLTexUnit::TFO_POINT);
+
+ // Initialize the image dimensions in GL
+ constexpr U8* undefined_data_for_now = nullptr;
+ gGL.getTexUnit(0)->bind(stamp_image, false, true);
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width_rounded, height_rounded, 0, format, type, undefined_data_for_now);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ stamp_image->setSize(width_rounded, height_rounded, components);
+ stamp_image->setDiscardLevel(0);
+
+ // Manually set a subset of the image in GL
+ const U8* data = paint_in->mData.data();
+ const S32 data_width = paint_in->mWidthX;
+ const S32 data_height = paint_in->mWidthY;
+ constexpr S32 origin = 0;
+ // width = data_width; height = data_height. i.e.: Copy the full
+ // contents of data into the image.
+ stamp_image->setSubImage(data, data_width, data_height, origin, origin, /*width=*/data_width, /*height=*/data_height);
+ }
+
+ // Apply ("stamp") the paint to the render target
+ {
+ shader.bindTextureImageGL(LLShaderMgr::DIFFUSE_MAP, stamp_image);
+ const F32 width_fraction = F32(paint_in->mWidthX) / F32(width_rounded);
+ const F32 height_fraction = F32(paint_in->mWidthY) / F32(height_rounded);
+ shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, width_fraction, height_fraction);
+ buf->setBuffer();
+ buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0);
+ }
+
+ // Extract the result back into memory as an RGB paint
+ LLTerrainPaint::ptr_t paint_out = std::make_shared<LLTerrainPaint>();
+ {
+ paint_out->mStartX = paint_in->mStartX;
+ paint_out->mStartY = paint_in->mStartY;
+ paint_out->mWidthX = paint_in->mWidthX;
+ paint_out->mWidthY = paint_in->mWidthY;
+ paint_out->mBitDepth = 8; // Will be reduced to TerrainPaintBitDepth bits later
+ paint_out->mComponents = LLTerrainPaint::RGB;
+#ifdef SHOW_ASSERT
+ paint_out->assert_confined_to(tex);
+#endif
+ paint_out->confine_to(tex);
+ paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY);
+ constexpr GLint miplevel = 0;
+ const S32 x_offset = paint_out->mStartX;
+ const S32 y_offset = paint_out->mStartY;
+ const S32 width = paint_out->mWidthX;
+ const S32 height = paint_out->mWidthY;
+ constexpr GLenum pixformat = GL_RGB;
+ constexpr GLenum pixtype = GL_UNSIGNED_BYTE;
+ llassert(paint_out->mData.size() <= std::numeric_limits<GLsizei>::max());
+ const GLsizei buf_size = (GLsizei)paint_out->mData.size();
+ U8* pixels = paint_out->mData.data();
+ glReadPixels(x_offset, y_offset, width, height, pixformat, pixtype, pixels);
+ }
+
+ // Enqueue the result to the new paint queue, with bit depths per color
+ // channel reduced from 8 to 5, and reduced from RGBA (paintmap
+ // sub-rectangle update with alpha mask) to RGB (paintmap sub-rectangle
+ // update without alpha mask). This format is suitable for sending
+ // over the network.
+ // *TODO: At some point, queue_out will pass through a network
+ // round-trip which will reduce the bit depth, making the
+ // pre-conversion step not necessary.
+ queue_out.enqueue(paint_out);
+ LLCachedControl<U32> bit_depth(gSavedSettings, "TerrainPaintBitDepth");
+ queue_out.convertBitDepths(queue_out.size()-1, bit_depth);
+ }
+
+ queue_in.clear();
+
+ scratch_target.flush();
+
+ LLGLSLShader::unbind();
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+
+ return queue_out;
+}
+
+// static
+LLTerrainPaintQueue LLTerrainPaintMap::convertBrushQueueToPaintRGB(const LLViewerRegion& region, LLViewerTexture& tex, LLTerrainBrushQueue& queue_in)
+{
+ check_tex(tex);
+
+ // TODO: Avoid allocating a scratch render buffer and use mAuxillaryRT instead
+ // TODO: even if it means performing extra render operations to apply the brushes, in rare cases where the paints can't all fit within an area that can be represented by the buffer
+ LLRenderTarget scratch_target;
+ const S32 max_dim = llmax(tex.getWidth(), tex.getHeight());
+ scratch_target.allocate(max_dim, max_dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE,
+ LLTexUnit::eTextureMipGeneration::TMG_NONE);
+ if (!scratch_target.isComplete())
+ {
+ llassert(false);
+ LL_WARNS() << "Failed to allocate render target" << LL_ENDL;
+ return false;
+ }
+ gGL.getTexUnit(0)->disable();
+ stop_glerror();
+
+ scratch_target.bindTarget();
+ glClearColor(0, 0, 0, 0);
+ scratch_target.clear();
+ const F32 target_half_width = (F32)scratch_target.getWidth() / 2.0f;
+ const F32 target_half_height = (F32)scratch_target.getHeight() / 2.0f;
+
+ LLVertexBuffer* buf = get_paint_triangle_buffer();
+
+ // Update projection matrix and viewport
+ // *NOTE: gl_state_for_2d also sets the modelview matrix. This will be overridden later.
+ {
+ stop_glerror();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.ortho(-target_half_width, target_half_width, -target_half_height, target_half_height, 0.25f, 1.0f);
+ stop_glerror();
+ const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0);
+ glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight());
+ }
+
+ // View matrix
+ // Coordinates should be in pixels. 1.0f = 1 pixel on the framebuffer.
+ // Camera is centered in the middle of the framebuffer.
+ glm::mat4 view(glm::make_mat4((GLfloat*)OGL_TO_CFR_ROTATION));
+ {
+ LLViewerCamera camera;
+ const LLVector3 camera_origin(target_half_width, target_half_height, 0.5f);
+ const LLVector3 camera_look_down(target_half_width, target_half_height, 0.0f);
+ camera.lookAt(camera_origin, camera_look_down, LLVector3::y_axis);
+ camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth()));
+ GLfloat ogl_matrix[16];
+ camera.getOpenGLTransform(ogl_matrix);
+ view *= glm::make_mat4(ogl_matrix);
+ }
+
+ LLGLDisable stencil(GL_STENCIL_TEST);
+ LLGLDisable scissor(GL_SCISSOR_TEST);
+ LLGLEnable cull_face(GL_CULL_FACE);
+ LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS);
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ LLGLSLShader& shader = gTerrainStampProgram;
+ shader.bind();
+
+ // First, apply the paint map as the background
+ {
+ glm::mat4 model;
+ {
+ model = glm::scale(model, glm::vec3((F32)tex.getWidth(), (F32)tex.getHeight(), 1.0f));
+ model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
+ }
+ glm::mat4 modelview = view * model;
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.loadMatrix(glm::value_ptr(modelview));
+
+ shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, &tex);
+ // We care about the whole paintmap, which is already a power of two.
+ // Hence, TERRAIN_STAMP_SCALE = (1.0,1.0)
+ shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f);
+ buf->setBuffer();
+ buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0);
+ }
+
+ LLTerrainPaintQueue queue_out(LLTerrainPaint::RGB);
+
+ // Incrementally apply each brush stroke to the render target, then extract
+ // the result back into memory as an RGB paint.
+ // Put each result in queue_out.
+ const std::vector<LLTerrainBrush::ptr_t>& brush_list = queue_in.get();
+ for (size_t i = 0; i < brush_list.size(); ++i)
+ {
+ const LLTerrainBrush::ptr_t& brush_in = brush_list[i];
+
+ // Modelview matrix for the current brush
+ // View matrix is already computed. Just need the model matrix.
+ // Orthographic projection matrix is already updated
+ // *NOTE: Brush path information is in region space. It will need to be
+ // converted to paintmap pixel space before it makes sense.
+ F32 brush_width_x;
+ F32 brush_width_y;
+ F32 brush_start_x;
+ F32 brush_start_y;
+ {
+ F32 min_x = brush_in->mPath[0].mV[VX];
+ F32 max_x = min_x;
+ F32 min_y = brush_in->mPath[0].mV[VY];
+ F32 max_y = min_y;
+ for (size_t i = 1; i < brush_in->mPath.size(); ++i)
+ {
+ const F32 x = brush_in->mPath[i].mV[VX];
+ const F32 y = brush_in->mPath[i].mV[VY];
+ min_x = llmin(min_x, x);
+ max_x = llmax(max_x, x);
+ min_y = llmin(min_y, y);
+ max_y = llmax(max_y, y);
+ }
+ brush_width_x = brush_in->mBrushSize + (max_x - min_x);
+ brush_width_y = brush_in->mBrushSize + (max_y - min_y);
+ brush_start_x = min_x - (brush_in->mBrushSize / 2.0f);
+ brush_start_y = min_y - (brush_in->mBrushSize / 2.0f);
+ // Convert brush path information to paintmap pixel space from region
+ // space.
+ brush_width_x *= tex.getWidth() / region.getWidth();
+ brush_width_y *= tex.getHeight() / region.getWidth();
+ brush_start_x *= tex.getWidth() / region.getWidth();
+ brush_start_y *= tex.getHeight() / region.getWidth();
+ }
+ glm::mat4 model;
+ {
+ model = glm::scale(model, glm::vec3(brush_width_x, brush_width_y, 1.0f));
+ model = glm::translate(model, glm::vec3(brush_start_x, brush_start_y, 0.0f));
+ }
+ glm::mat4 modelview = view * model;
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.loadMatrix(glm::value_ptr(modelview));
+
+ // Apply the "brush" to the render target
+ {
+ // TODO: Use different shader for this - currently this is using the stamp shader. The white image is just a placeholder for now
+ shader.bindTexture(LLShaderMgr::DIFFUSE_MAP, LLViewerFetchedTexture::sWhiteImagep);
+ shader.uniform2f(LLShaderMgr::TERRAIN_STAMP_SCALE, 1.0f, 1.0f);
+ buf->setBuffer();
+ buf->draw(LLRender::TRIANGLES, buf->getIndicesSize(), 0);
+ }
+
+ // Extract the result back into memory as an RGB paint
+ LLTerrainPaint::ptr_t paint_out = std::make_shared<LLTerrainPaint>();
+ {
+ paint_out->mStartX = U16(floor(brush_start_x));
+ paint_out->mStartY = U16(floor(brush_start_y));
+ const F32 dX = brush_start_x - F32(paint_out->mStartX);
+ const F32 dY = brush_start_y - F32(paint_out->mStartY);
+ paint_out->mWidthX = U16(ceil(brush_width_x + dX));
+ paint_out->mWidthY = U16(ceil(brush_width_y + dY));
+ paint_out->mBitDepth = 8; // Will be reduced to TerrainPaintBitDepth bits later
+ paint_out->mComponents = LLTerrainPaint::RGB;
+ // The brush strokes are expected to sometimes partially venture
+ // outside of the paintmap bounds.
+ paint_out->confine_to(tex);
+ paint_out->mData.resize(paint_out->mComponents * paint_out->mWidthX * paint_out->mWidthY);
+ constexpr GLint miplevel = 0;
+ const S32 x_offset = paint_out->mStartX;
+ const S32 y_offset = paint_out->mStartY;
+ const S32 width = paint_out->mWidthX;
+ const S32 height = paint_out->mWidthY;
+ constexpr GLenum pixformat = GL_RGB;
+ constexpr GLenum pixtype = GL_UNSIGNED_BYTE;
+ llassert(paint_out->mData.size() <= std::numeric_limits<GLsizei>::max());
+ const GLsizei buf_size = (GLsizei)paint_out->mData.size();
+ U8* pixels = paint_out->mData.data();
+ glReadPixels(x_offset, y_offset, width, height, pixformat, pixtype, pixels);
+ }
+
+ // Enqueue the result to the new paint queue, with bit depths per color
+ // channel reduced from 8 to 5, and reduced from RGBA (paintmap
+ // sub-rectangle update with alpha mask) to RGB (paintmap sub-rectangle
+ // update without alpha mask). This format is suitable for sending
+ // over the network.
+ // *TODO: At some point, queue_out will pass through a network
+ // round-trip which will reduce the bit depth, making the
+ // pre-conversion step not necessary.
+ queue_out.enqueue(paint_out);
+ LLCachedControl<U32> bit_depth(gSavedSettings, "TerrainPaintBitDepth");
+ queue_out.convertBitDepths(queue_out.size()-1, bit_depth);
+ }
+
+ queue_in.clear();
+
+ scratch_target.flush();
+
+ LLGLSLShader::unbind();
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+
+ return queue_out;
+}
+
+template<typename T>
+LLTerrainQueue<T>::LLTerrainQueue(LLTerrainQueue<T>& other)
+{
+ *this = other;
+}
+
+template<typename T>
+LLTerrainQueue<T>& LLTerrainQueue<T>::operator=(LLTerrainQueue<T>& other)
+{
+ mList = other.mList;
+ return *this;
+}
+
+template<typename T>
+bool LLTerrainQueue<T>::enqueue(std::shared_ptr<T>& t, bool dry_run)
+{
+ if (!dry_run) { mList.push_back(t); }
+ return true;
+}
+
+template<typename T>
+bool LLTerrainQueue<T>::enqueue(std::vector<std::shared_ptr<T>>& list)
+{
+ constexpr bool dry_run = true;
+ for (auto& t : list)
+ {
+ if (!enqueue(t, dry_run)) { return false; }
+ }
+ for (auto& t : list)
+ {
+ enqueue(t);
+ }
+ return true;
+}
+
+template<typename T>
+size_t LLTerrainQueue<T>::size() const
+{
+ return mList.size();
+}
+
+template<typename T>
+bool LLTerrainQueue<T>::empty() const
+{
+ return mList.empty();
+}
+
+template<typename T>
+void LLTerrainQueue<T>::clear()
+{
+ mList.clear();
+}
+
+void LLTerrainPaint::assert_confined_to(const LLTexture& tex) const
+{
+ llassert(mStartX >= 0 && mStartX < tex.getWidth());
+ llassert(mStartY >= 0 && mStartY < tex.getHeight());
+ llassert(mWidthX <= tex.getWidth() - mStartX);
+ llassert(mWidthY <= tex.getHeight() - mStartY);
+}
+
+void LLTerrainPaint::confine_to(const LLTexture& tex)
+{
+ mStartX = llmax(mStartX, 0);
+ mStartY = llmax(mStartY, 0);
+ mWidthX = llmin(mWidthX, tex.getWidth() - mStartX);
+ mWidthY = llmin(mWidthY, tex.getHeight() - mStartY);
+ assert_confined_to(tex);
+}
+
+LLTerrainPaintQueue::LLTerrainPaintQueue(U8 components)
+: mComponents(components)
+{
+ llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA);
+}
+
+LLTerrainPaintQueue::LLTerrainPaintQueue(LLTerrainPaintQueue& other)
+: LLTerrainQueue<LLTerrainPaint>(other)
+, mComponents(other.mComponents)
+{
+ llassert(mComponents == LLTerrainPaint::RGB || mComponents == LLTerrainPaint::RGBA);
+}
+
+LLTerrainPaintQueue& LLTerrainPaintQueue::operator=(LLTerrainPaintQueue& other)
+{
+ LLTerrainQueue<LLTerrainPaint>::operator=(other);
+ mComponents = other.mComponents;
+ return *this;
+}
+
+bool LLTerrainPaintQueue::enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run)
+{
+ llassert(paint);
+ if (!paint) { return false; }
+
+ // The paint struct should be pre-validated before this code is reached.
+ llassert(!paint->mData.empty());
+ // The internal paint map image is currently 8 bits, so that's the maximum
+ // allowed bit depth.
+ llassert(paint->mBitDepth > 0 && paint->mBitDepth <= 8);
+ llassert(paint->mData.size() == (mComponents * paint->mWidthX * paint->mWidthY));
+ llassert(paint->mWidthX > 0);
+ llassert(paint->mWidthY > 0);
+#ifdef SHOW_ASSERT
+ static LLCachedControl<U32> max_texture_width(gSavedSettings, "RenderMaxTextureResolution", 2048);
+#endif
+ llassert(paint->mWidthX <= max_texture_width);
+ llassert(paint->mWidthY <= max_texture_width);
+ llassert(paint->mStartX < max_texture_width);
+ llassert(paint->mStartY < max_texture_width);
+
+ return LLTerrainQueue<LLTerrainPaint>::enqueue(paint, dry_run);
+}
+
+bool LLTerrainPaintQueue::enqueue(LLTerrainPaintQueue& queue)
+{
+ return LLTerrainQueue<LLTerrainPaint>::enqueue(queue.mList);
+}
+
+void LLTerrainPaintQueue::convertBitDepths(size_t index, U8 target_bit_depth)
+{
+ llassert(target_bit_depth > 0 && target_bit_depth <= 8);
+ llassert(index < mList.size());
+
+ LLTerrainPaint::ptr_t& paint = mList[index];
+ if (paint->mBitDepth == target_bit_depth) { return; }
+
+ const F32 old_bit_max = F32((1 << paint->mBitDepth) - 1);
+ const F32 new_bit_max = F32((1 << target_bit_depth) - 1);
+ const F32 bit_conversion_factor = new_bit_max / old_bit_max;
+
+ for (U8& color : paint->mData)
+ {
+ color = (U8)llround(F32(color) * bit_conversion_factor);
+ }
+
+ paint->mBitDepth = target_bit_depth;
+}
+
+LLTerrainBrushQueue::LLTerrainBrushQueue()
+: LLTerrainQueue<LLTerrainBrush>()
+{
+}
+
+LLTerrainBrushQueue::LLTerrainBrushQueue(LLTerrainBrushQueue& other)
+: LLTerrainQueue<LLTerrainBrush>(other)
+{
+}
+
+LLTerrainBrushQueue& LLTerrainBrushQueue::operator=(LLTerrainBrushQueue& other)
+{
+ LLTerrainQueue<LLTerrainBrush>::operator=(other);
+ return *this;
+}
+
+bool LLTerrainBrushQueue::enqueue(LLTerrainBrush::ptr_t& brush, bool dry_run)
+{
+ llassert(brush->mBrushSize > 0);
+ llassert(!brush->mPath.empty());
+ llassert(brush->mPathOffset < brush->mPath.size());
+ llassert(brush->mPathOffset < 2); // Harmless, but doesn't do anything useful, so might be a sign of implementation error
+ return LLTerrainQueue<LLTerrainBrush>::enqueue(brush, dry_run);
+}
+
+bool LLTerrainBrushQueue::enqueue(LLTerrainBrushQueue& queue)
+{
+ return LLTerrainQueue<LLTerrainBrush>::enqueue(queue.mList);
+}
+
+template class LLTerrainQueue<LLTerrainPaint>;
+template class LLTerrainQueue<LLTerrainBrush>;
diff --git a/indra/newview/llterrainpaintmap.h b/indra/newview/llterrainpaintmap.h
index 66827862c5..d4859b747b 100644
--- a/indra/newview/llterrainpaintmap.h
+++ b/indra/newview/llterrainpaintmap.h
@@ -26,9 +26,20 @@
#pragma once
+#include <memory>
+#include <vector>
+
+#include "stdtypes.h"
+#include "v2math.h"
+
+class LLTexture;
class LLViewerRegion;
class LLViewerTexture;
+class LLTerrainPaintQueue;
+class LLTerrainBrushQueue;
+// TODO: Terrain painting across regions. Assuming painting is confined to one
+// region for now.
class LLTerrainPaintMap
{
public:
@@ -39,4 +50,121 @@ public:
// to type TERRAIN_PAINT_TYPE_PBR_PAINTMAP.
// Returns true if successful
static bool bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex);
+
+ // This operation clears the queue
+ // TODO: Decide if clearing the queue is needed - seems inconsistent
+ static void applyPaintQueueRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue);
+
+ static LLTerrainPaintQueue convertPaintQueueRGBAToRGB(LLViewerTexture& tex, LLTerrainPaintQueue& queue_in);
+ // TODO: Implement (it's similar to convertPaintQueueRGBAToRGB but different shader + need to calculate the dimensions + need a different vertex buffer for each brush stroke)
+ static LLTerrainPaintQueue convertBrushQueueToPaintRGB(const LLViewerRegion& region, LLViewerTexture& tex, LLTerrainBrushQueue& queue_in);
+};
+
+template<typename T>
+class LLTerrainQueue
+{
+public:
+ LLTerrainQueue() = default;
+ LLTerrainQueue(LLTerrainQueue<T>& other);
+ LLTerrainQueue& operator=(LLTerrainQueue<T>& other);
+
+ bool enqueue(std::shared_ptr<T>& t, bool dry_run = false);
+ size_t size() const;
+ bool empty() const;
+ void clear();
+
+ const std::vector<std::shared_ptr<T>>& get() const { return mList; }
+
+protected:
+ bool enqueue(std::vector<std::shared_ptr<T>>& list);
+
+ std::vector<std::shared_ptr<T>> mList;
+};
+
+// Enqueued paint operations, in texture coordinates.
+// mData is always RGB or RGBA (determined by mComponents), with each U8
+// storing one color with a max value of (1 >> mBitDepth) - 1
+struct LLTerrainPaint
+{
+ using ptr_t = std::shared_ptr<LLTerrainPaint>;
+
+ U16 mStartX;
+ U16 mStartY;
+ U16 mWidthX;
+ U16 mWidthY;
+ U8 mBitDepth;
+ U8 mComponents;
+ static constexpr U8 RGB = 3;
+ static constexpr U8 RGBA = 4;
+ std::vector<U8> mData;
+
+ // Asserts that this paint's start/width fit within the bounds of the
+ // provided texture dimensions.
+ void assert_confined_to(const LLTexture& tex) const;
+ // Confines this paint's start/width so it fits within the bounds of the
+ // provided texture dimensions.
+ // Does not allocate mData.
+ void confine_to(const LLTexture& tex);
+};
+
+class LLTerrainPaintQueue : public LLTerrainQueue<LLTerrainPaint>
+{
+public:
+ LLTerrainPaintQueue() = delete;
+ // components determines what type of LLTerrainPaint is allowed. Must be 3 (RGB) or 4 (RGBA)
+ LLTerrainPaintQueue(U8 components);
+ LLTerrainPaintQueue(LLTerrainPaintQueue& other);
+ LLTerrainPaintQueue& operator=(LLTerrainPaintQueue& other);
+
+ bool enqueue(LLTerrainPaint::ptr_t& paint, bool dry_run = false);
+ bool enqueue(LLTerrainPaintQueue& queue);
+
+ U8 getComponents() const { return mComponents; }
+ // Convert mBitDepth for the LLTerrainPaint in the queue at index
+ // If mBitDepth is already equal to target_bit_depth, no conversion takes
+ // place.
+ // It is currently the responsibility of the paint queue to convert
+ // incoming bits to the right bit depth for the paintmap (this could
+ // change in the future).
+ void convertBitDepths(size_t index, U8 target_bit_depth);
+
+private:
+ U8 mComponents;
+};
+
+struct LLTerrainBrush
+{
+ using ptr_t = std::shared_ptr<LLTerrainBrush>;
+
+ // Width of the brush in region space. The brush is a square texture with
+ // alpha.
+ F32 mBrushSize;
+ // Brush path points in region space, excluding the vertical axis, which
+ // does not contribute to the paint map.
+ std::vector<LLVector2> mPath;
+ // Offset of the brush path to actually start drawing at. An offset of 0
+ // indicates that a brush stroke has just started (i.e. the user just
+ // pressed down the mouse button). An offset greater than 0 indicates the
+ // continuation of a brush stroke. Skipped entries in mPath are not drawn
+ // directly, but are used for stroke orientation and path interpolation.
+ // TODO: For the initial implementation, mPathOffset will be 0 and mPath
+ // will be of length of at most 1, leading to discontinuous paint paths.
+ // Then, mPathOffset may be 1 or 0, 1 indicating the continuation of a
+ // stroke with linear interpolation. It is unlikely that we will implement
+ // anything more sophisticated than that for now.
+ U8 mPathOffset;
+ // Indicates if this is the end of the brush stroke. Can occur if the mouse
+ // button is lifted, or if the mouse temporarily stops while held down.
+ bool mPathEnd;
+};
+
+class LLTerrainBrushQueue : public LLTerrainQueue<LLTerrainBrush>
+{
+public:
+ LLTerrainBrushQueue();
+ LLTerrainBrushQueue(LLTerrainBrushQueue& other);
+ LLTerrainBrushQueue& operator=(LLTerrainBrushQueue& other);
+
+ bool enqueue(LLTerrainBrush::ptr_t& brush, bool dry_run = false);
+ bool enqueue(LLTerrainBrushQueue& queue);
};
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 35057a910a..c51e90e632 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -185,7 +185,9 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
mSetImageAssetIDCallback(NULL),
mOnUpdateImageStatsCallback(NULL),
mBakeTextureEnabled(false),
- mInventoryPickType(pick_type)
+ mLocalTextureEnabled(false),
+ mInventoryPickType(pick_type),
+ mSelectionSource(PICKER_UNKNOWN)
{
mCanApplyImmediately = can_apply_immediately;
buildFromFile("floater_texture_ctrl.xml");
@@ -203,6 +205,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti
mNoCopyTextureSelected = false;
mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
mImageAssetID = image_id;
+ mSelectionSource = PICKER_UNKNOWN;
if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID))
{
@@ -211,6 +214,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti
mModeSelector->selectByValue(2);
onModeSelect(0,this);
}
+ mSelectionSource = PICKER_BAKE;
}
else
{
@@ -257,6 +261,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti
getChild<LLUICtrl>("apply_immediate_check")->setValue(false);
mNoCopyTextureSelected = true;
}
+ mSelectionSource = PICKER_INVENTORY;
}
if (set_selection)
@@ -276,6 +281,7 @@ void LLFloaterTexturePicker::setImageIDFromItem(const LLInventoryItem* itemp, bo
asset_id = BLANK_MATERIAL_ASSET_ID;
}
setImageID(asset_id, set_selection);
+ mSelectionSource = PICKER_INVENTORY;
}
void LLFloaterTexturePicker::setActive( bool active )
@@ -524,6 +530,8 @@ bool LLFloaterTexturePicker::handleKeyHere(KEY key, MASK mask)
void LLFloaterTexturePicker::onOpen(const LLSD& key)
{
if (sLastPickerMode != 0
+ && (mLocalTextureEnabled || sLastPickerMode != 1)
+ && (mBakeTextureEnabled || sLastPickerMode != 2)
&& mModeSelector->selectByValue(sLastPickerMode))
{
changeMode();
@@ -890,10 +898,15 @@ void LLFloaterTexturePicker::commitCallback(LLTextureCtrl::ETexturePickOp op)
{
return;
}
+
LLUUID asset_id = mImageAssetID;
LLUUID inventory_id;
LLUUID tracking_id;
- LLPickerSource mode = (LLPickerSource)mModeSelector->getValue().asInteger();
+ LLPickerSource mode = mSelectionSource;
+ if (mode == PICKER_UNKNOWN)
+ {
+ mode = (LLPickerSource)mModeSelector->getValue().asInteger();
+ }
switch (mode)
{
@@ -919,11 +932,13 @@ void LLFloaterTexturePicker::commitCallback(LLTextureCtrl::ETexturePickOp op)
}
else
{
+ // Item's asset id changed?
mode = PICKER_UNKNOWN; // source of id unknown
}
}
else
{
+ // Item could have been removed from inventory
mode = PICKER_UNKNOWN; // source of id unknown
}
break;
@@ -947,6 +962,7 @@ void LLFloaterTexturePicker::commitCallback(LLTextureCtrl::ETexturePickOp op)
}
else
{
+ // List could have been emptied, with local image still selected
asset_id = mImageAssetID;
mode = PICKER_UNKNOWN; // source of id unknown
}
@@ -1000,18 +1016,6 @@ void LLFloaterTexturePicker::onBtnNone(void* userdata)
self->commitIfImmediateSet();
}
-/*
-// static
-void LLFloaterTexturePicker::onBtnRevert(void* userdata)
-{
- LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
- self->setImageID( self->mOriginalImageAssetID );
- // TODO: Change this to tell the owner to cancel. It needs to be
- // smart enough to restore multi-texture selections.
- self->mOwner->onFloaterCommit();
- self->mViewModel->resetDirty();
-}*/
-
// static
void LLFloaterTexturePicker::onBtnCancel(void* userdata)
{
@@ -1029,8 +1033,11 @@ void LLFloaterTexturePicker::onBtnCancel(void* userdata)
void LLFloaterTexturePicker::onBtnSelect(void* userdata)
{
LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
- if (self->mOnFloaterCommitCallback)
+ if (self->mViewModel->isDirty() && self->mOnFloaterCommitCallback)
{
+ // If nothing changed, don't commit.
+ // ex: can overwrite multiple original textures with a single one.
+ // or resubmit something thus overriding some other source of change
self->commitCallback(LLTextureCtrl::TEXTURE_SELECT);
}
self->closeFloater();
@@ -1067,8 +1074,18 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem
{
mNoCopyTextureSelected = true;
}
+ bool was_dirty = mViewModel->isDirty();
setImageIDFromItem(itemp, false);
- mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
+ if (user_action)
+ {
+ mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
+ setTentative( false );
+ }
+ else if (!was_dirty)
+ {
+ // setImageIDFromItem could have dropped the flag
+ mViewModel->resetDirty();
+ }
if(!mPreviewSettingChanged)
{
@@ -1215,6 +1232,8 @@ void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata)
inworld_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id);
}
+ self->mSelectionSource = PICKER_LOCAL;
+
if (self->mSetImageAssetIDCallback)
{
self->mSetImageAssetIDCallback(inworld_id);
@@ -1312,6 +1331,7 @@ void LLFloaterTexturePicker::onBakeTextureSelect(LLUICtrl* ctrl, void *user_data
// only commit intentional selections, not implicit ones
self->commitIfImmediateSet();
}
+ self->mSelectionSource = PICKER_BAKE;
}
void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply, bool inworld_image)
@@ -1490,7 +1510,13 @@ void LLFloaterTexturePicker::refreshInventoryFilter()
void LLFloaterTexturePicker::setLocalTextureEnabled(bool enabled)
{
+ mLocalTextureEnabled = enabled;
mModeSelector->setEnabledByValue(1, enabled);
+ if (!enabled && (mModeSelector->getValue().asInteger() == 2))
+ {
+ mModeSelector->selectByValue(0);
+ onModeSelect(0, this);
+ }
}
void LLFloaterTexturePicker::setBakeTextureEnabled(bool enabled)
@@ -1627,6 +1653,7 @@ void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te )
// no copy texture
mNoCopyTextureSelected = true;
}
+ mSelectionSource = PICKER_INVENTORY;
commitIfImmediateSet();
}
@@ -1877,11 +1904,9 @@ void LLTextureCtrl::showPicker(bool take_focus)
if (texture_floaterp)
{
texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLTextureCtrl::onFloaterCommit, this, _1, _2, _3, _4, _5));
- }
- if (texture_floaterp)
- {
texture_floaterp->setSetImageAssetIDCallback(boost::bind(&LLTextureCtrl::setImageAssetID, this, _1));
+ texture_floaterp->setLocalTextureEnabled(mAllowLocalTexture);
texture_floaterp->setBakeTextureEnabled(mBakeTextureEnabled && mInventoryPickType != PICK_MATERIAL);
}
@@ -1891,12 +1916,6 @@ void LLTextureCtrl::showPicker(bool take_focus)
floaterp->openFloater();
}
- LLFloaterTexturePicker* picker_floater = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
- if (picker_floater)
- {
- picker_floater->setLocalTextureEnabled(mAllowLocalTexture);
- }
-
if (take_focus)
{
floaterp->setFocus(true);
@@ -2076,6 +2095,16 @@ void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb)
}
}
+void LLTextureCtrl::setAllowLocalTexture(bool b)
+{
+ mAllowLocalTexture = b;
+ LLFloaterTexturePicker* picker_floater = dynamic_cast<LLFloaterTexturePicker*>(mFloaterHandle.get());
+ if (picker_floater)
+ {
+ picker_floater->setLocalTextureEnabled(mAllowLocalTexture);
+ }
+}
+
void LLTextureCtrl::setImageAssetName(const std::string& name)
{
LLPointer<LLUIImage> imagep = LLUI::getUIImage(name);
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index df5e763139..93819a614c 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -181,7 +181,7 @@ public:
void setAllowNoTexture( bool b ) { mAllowNoTexture = b; }
bool getAllowNoTexture() const { return mAllowNoTexture; }
- void setAllowLocalTexture(bool b) { mAllowLocalTexture = b; }
+ void setAllowLocalTexture(bool b);
bool getAllowLocalTexture() const { return mAllowLocalTexture; }
const LLUUID& getImageItemID() { return mImageItemID; }
@@ -447,6 +447,7 @@ private:
S32 mMaxDim;
S32 mMinDim;
EPickInventoryType mInventoryPickType;
+ LLPickerSource mSelectionSource;
texture_selected_callback mTextureSelectedCallback;
@@ -456,6 +457,7 @@ private:
set_on_update_image_stats_callback mOnUpdateImageStatsCallback;
bool mBakeTextureEnabled;
+ bool mLocalTextureEnabled;
static S32 sLastPickerMode;
};
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index ed91214bd0..160674d3d8 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2474,12 +2474,13 @@ LLTextureFetch::~LLTextureFetch()
}
S32 LLTextureFetch::createRequest(FTType f_type, const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
- S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux, bool can_use_http)
+ S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux, bool can_use_http, S32& worker_discard)
{
LL_PROFILE_ZONE_SCOPED;
+ worker_discard = -1;
if (mDebugPause)
{
- return -1;
+ return FETCH_REQUEST_CREATION_FAILED;
}
if (f_type == FTT_SERVER_BAKE)
@@ -2495,7 +2496,7 @@ S32 LLTextureFetch::createRequest(FTType f_type, const std::string& url, const L
<< host << " != " << worker->mHost << LL_ENDL;
removeRequest(worker, true);
worker = NULL;
- return -1;
+ return FETCH_REQUEST_ABORTED;
}
}
@@ -2548,13 +2549,14 @@ S32 LLTextureFetch::createRequest(FTType f_type, const std::string& url, const L
{
if (worker->wasAborted())
{
- return -1; // need to wait for previous aborted request to complete
+ return FETCH_REQUEST_ABORTED; // need to wait for previous aborted request to complete
}
+ worker_discard = desired_discard;
worker->lockWorkMutex(); // +Mw
if (worker->mState == LLTextureFetchWorker::DONE && worker->mDesiredSize == llmax(desired_size, TEXTURE_CACHE_ENTRY_SIZE) && worker->mDesiredDiscard == desired_discard) {
worker->unlockWorkMutex(); // -Mw
- return -1; // similar request has failed or is in a transitional state
+ return FETCH_REQUEST_EXISTS; // similar request has failed or is in a transitional state
}
worker->mActiveCount++;
worker->mNeedsAux = needs_aux;
@@ -2588,11 +2590,12 @@ S32 LLTextureFetch::createRequest(FTType f_type, const std::string& url, const L
worker->mNeedsAux = needs_aux;
worker->setCanUseHTTP(can_use_http) ;
worker->unlockWorkMutex(); // -Mw
+ worker_discard = desired_discard;
}
LL_DEBUGS(LOG_TXT) << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type)
<< " Discard: " << desired_discard << " size " << desired_size << LL_ENDL;
- return desired_discard;
+ return FETCH_REQUEST_OK;
}
// Threads: T*
//
@@ -2832,7 +2835,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
{
LL_PROFILE_ZONE_SCOPED;
- mRequestQueue.tryPost([=]()
+ mRequestQueue.tryPost([=, this]()
{
LLTextureFetchWorker* worker = getWorker(id);
if (worker)
@@ -3523,8 +3526,8 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
//if (! gViewerAssetStatsThread1)
// return true;
- static volatile bool reporting_started(false);
- static volatile S32 report_sequence(0);
+ static std::atomic<bool> reporting_started(false);
+ static std::atomic<S32> report_sequence(0);
// In mStatsSD, we have a copy we own of the LLSD representation
// of the asset stats. Add some additional fields and ship it off.
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 3405f76e37..c2296135e2 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -76,9 +76,14 @@ public:
// Threads: Tmain
void shutDownImageDecodeThread();
+ static constexpr S32 FETCH_REQUEST_OK = 0;
+ static constexpr S32 FETCH_REQUEST_CREATION_FAILED = -1;
+ static constexpr S32 FETCH_REQUEST_ABORTED = -2;
+ static constexpr S32 FETCH_REQUEST_EXISTS = -3;
// Threads: T* (but Tmain mostly)
+ // returns discard on success, fail code otherwise
S32 createRequest(FTType f_type, const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
- S32 w, S32 h, S32 c, S32 discard, bool needs_aux, bool can_use_http);
+ S32 w, S32 h, S32 c, S32 discard, bool needs_aux, bool can_use_http, S32& worker_disacrd);
// Requests that a fetch operation be deleted from the queue.
// If @cancel is true, also stops any I/O operations pending.
diff --git a/indra/newview/llthumbnailctrl.cpp b/indra/newview/llthumbnailctrl.cpp
index ae21d3e733..b077262f06 100644
--- a/indra/newview/llthumbnailctrl.cpp
+++ b/indra/newview/llthumbnailctrl.cpp
@@ -111,7 +111,9 @@ void LLThumbnailCtrl::draw()
gl_draw_scaled_image( draw_rect.mLeft, draw_rect.mBottom, draw_rect.getWidth(), draw_rect.getHeight(), mTexturep, UI_VERTEX_COLOR % alpha);
- mTexturep->setKnownDrawSize(draw_rect.getWidth(), draw_rect.getHeight());
+ // Thumbnails are usually 256x256 or smaller, either report that or
+ // some high value to get image with higher priority
+ mTexturep->setKnownDrawSize(MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
}
else if( mImagep.notNull() )
{
@@ -238,12 +240,8 @@ void LLThumbnailCtrl::initImage()
{
// Should it support baked textures?
mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_THUMBNAIL);
-
mTexturep->forceToSaveRawImage(0);
-
- S32 desired_draw_width = MAX_IMAGE_SIZE;
- S32 desired_draw_height = MAX_IMAGE_SIZE;
- mTexturep->setKnownDrawSize(desired_draw_width, desired_draw_height);
+ mTexturep->setKnownDrawSize(MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
}
}
else if (tvalue.isString())
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index 84503e66a5..db56544502 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -43,34 +43,21 @@ LLToastLifeTimer::LLToastLifeTimer(LLToast* toast, F32 period)
{
}
-/*virtual*/
bool LLToastLifeTimer::tick()
{
- if (mEventTimer.hasExpired())
- {
- mToast->expire();
- }
+ mToast->expire();
return false;
}
-void LLToastLifeTimer::stop()
-{
- mEventTimer.stop();
-}
-
-void LLToastLifeTimer::start()
-{
- mEventTimer.start();
-}
-
void LLToastLifeTimer::restart()
{
- mEventTimer.reset();
+ // start() discards any previously-running mTimer
+ start();
}
bool LLToastLifeTimer::getStarted()
{
- return mEventTimer.getStarted();
+ return isRunning();
}
void LLToastLifeTimer::setPeriod(F32 period)
@@ -78,13 +65,6 @@ void LLToastLifeTimer::setPeriod(F32 period)
mPeriod = period;
}
-F32 LLToastLifeTimer::getRemainingTimeF32()
-{
- F32 et = mEventTimer.getElapsedTimeF32();
- if (!getStarted() || et > mPeriod) return 0.0f;
- return mPeriod - et;
-}
-
//--------------------------------------------------------------------------
LLToast::Params::Params()
: can_fade("can_fade", true),
@@ -337,7 +317,7 @@ void LLToast::setFading(bool transparent)
F32 LLToast::getTimeLeftToLive()
{
- F32 time_to_live = mTimer->getRemainingTimeF32();
+ F32 time_to_live = mTimer->getRemaining();
if (!mIsFading)
{
@@ -421,7 +401,7 @@ void LLToast::setVisible(bool show)
if(mHideBtn)
mHideBtn->setVisible(show);
}
- LLFloater::setVisible(show);
+ LLModalDialog::setVisible(show);
if (mPanel
&& !mPanel->isDead()
&& mWrapperPanel
diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h
index cf116bfadf..dd2ced7352 100644
--- a/indra/newview/lltoast.h
+++ b/indra/newview/lltoast.h
@@ -53,15 +53,11 @@ public:
LLToastLifeTimer(LLToast* toast, F32 period);
/*virtual*/
- bool tick();
- void stop();
- void start();
+ bool tick() override;
void restart();
bool getStarted();
void setPeriod(F32 period);
- F32 getRemainingTimeF32();
- LLTimer& getEventTimer() { return mEventTimer;}
private :
LLToast* mToast;
};
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index 3c3440d41a..95653dc19b 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -87,10 +87,21 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi
std::string timeStr = "[" + LLTrans::getString("TimeWeek") + "], ["
+ LLTrans::getString("TimeMonth") + "]/["
+ LLTrans::getString("TimeDay") + "]/["
- + LLTrans::getString("TimeYear") + "] ["
- + LLTrans::getString("TimeHour") + "]:["
- + LLTrans::getString("TimeMin") + "] ["
- + LLTrans::getString("TimeTimezone") + "]";
+ + LLTrans::getString("TimeYear") + "] [";
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ if (use_24h)
+ {
+ timeStr += LLTrans::getString("TimeHour") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeTimezone") + "]";
+ }
+ else
+ {
+ timeStr += LLTrans::getString("TimeHour12") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeAMPM") + "] ["
+ + LLTrans::getString("TimeTimezone") + "]";
+ }
const LLDate timeStamp = notification->getDate();
LLDate notice_date = timeStamp.notNull() ? timeStamp : payload["received_time"].asDate();
diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp
index 42ee30409d..df79af4926 100644
--- a/indra/newview/lltoastimpanel.cpp
+++ b/indra/newview/lltoastimpanel.cpp
@@ -87,7 +87,10 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif
{
LLAvatarName avatar_name;
LLAvatarNameCache::get(p.avatar_id, &avatar_name);
- p.message = "[From " + avatar_name.getDisplayName() + "]\n" + p.message;
+ // move Lua prefix from the message field to the [From] field
+ auto [message, is_lua] = LLStringUtil::withoutPrefix(p.message, LUA_PREFIX);
+ std::string prefix = is_lua ? "LUA - " : "";
+ p.message = "[From " + prefix + avatar_name.getDisplayName() + "]\n" + message;
}
style_params.font.style = "NORMAL";
mMessage->setText(p.message, style_params);
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 6d0704a469..58c01269f7 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -2145,7 +2145,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
{
if(mSource == SOURCE_LIBRARY)
{
- LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0));
+ LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, false));
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
@@ -2156,7 +2156,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
}
else
{
- rez_attachment(item, 0);
+ rez_attachment(item, 0, false);
}
}
return ACCEPT_YES_SINGLE;
diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp
index 07963a7bed..2ffb571201 100644
--- a/indra/newview/lltoolmgr.cpp
+++ b/indra/newview/lltoolmgr.cpp
@@ -84,9 +84,9 @@ LLToolMgr::LLToolMgr()
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Active", boost::bind(&LLToolMgr::inEdit, this));
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&LLToolMgr::canEdit, this));
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.EnabledOrActive", boost::bind(&LLToolMgr::buildEnabledOrActive, this));
- LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this, _2));
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", { boost::bind(&LLToolMgr::toggleBuildMode, this, _2) });
LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Marketplace.Enabled", boost::bind(&LLToolMgr::canAccessMarketplace, this));
- LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Marketplace.Toggle", boost::bind(&LLToolMgr::toggleMarketplace, this, _2));
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Marketplace.Toggle", { boost::bind(&LLToolMgr::toggleMarketplace, this, _2) });
gToolNull = new LLTool(LLStringUtil::null); // Does nothing
setCurrentTool(gToolNull);
diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp
index b15bb5efd5..2ac5d6b6b1 100644
--- a/indra/newview/lltoolplacer.cpp
+++ b/indra/newview/lltoolplacer.cpp
@@ -164,13 +164,17 @@ bool LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
bool b_hit_land = false;
S32 hit_face = -1;
LLViewerObject* hit_obj = NULL;
- U8 state = 0;
bool success = raycastForNewObjPos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp );
if( !success )
{
return false;
}
+ return rezNewObject(pcode,hit_obj, hit_face, b_hit_land, ray_start_region, ray_end_region, regionp, use_physics);
+}
+bool LLToolPlacer::rezNewObject(LLPCode pcode, LLViewerObject * hit_obj, S32 hit_face, bool b_hit_land, LLVector3 ray_start_region,
+ LLVector3 ray_end_region, LLViewerRegion* regionp, U8 use_physics)
+{
if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
{
// Can't create objects on avatars or attachments
@@ -195,6 +199,8 @@ bool LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
bool create_selected = false;
LLVolumeParams volume_params;
+ U8 state = 0;
+
switch (pcode)
{
case LL_PCODE_LEGACY_GRASS:
diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h
index f9501f83b2..92446c319b 100644
--- a/indra/newview/lltoolplacer.h
+++ b/indra/newview/lltoolplacer.h
@@ -50,6 +50,10 @@ public:
static void setObjectType( LLPCode type ) { sObjectType = type; }
static LLPCode getObjectType() { return sObjectType; }
+// static bool addObject(LLPCode pcode, S32 x, S32 y, U8 use_physics);
+ static bool rezNewObject(LLPCode pcode, LLViewerObject* hit_obj, S32 hit_face, bool b_hit_land, LLVector3 ray_start_region,
+ LLVector3 ray_end_region, LLViewerRegion *regionp, U8 use_physics);
+
protected:
static LLPCode sObjectType;
diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp
index 5ccda7d4eb..3bd459f5b0 100644
--- a/indra/newview/lltoolselect.cpp
+++ b/indra/newview/lltoolselect.cpp
@@ -55,17 +55,17 @@ LLToolSelect::LLToolSelect( LLToolComposite* composite )
: LLTool( std::string("Select"), composite ),
mIgnoreGroup( false )
{
- }
+}
// True if you selected an object.
bool LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask)
{
// do immediate pick query
bool pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");
- bool pick_transparent = gSavedSettings.getBOOL("SelectInvisibleObjects");
- bool pick_reflection_probe = gSavedSettings.getBOOL("SelectReflectionProbes");
+ static LLCachedControl<bool> select_invisible_objects(gSavedSettings, "SelectInvisibleObjects");
+ static LLCachedControl<bool> select_reflection_probes(gSavedSettings, "SelectReflectionProbes");
- mPick = gViewerWindow->pickImmediate(x, y, pick_transparent, pick_rigged, false, true, pick_reflection_probe);
+ mPick = gViewerWindow->pickImmediate(x, y, select_invisible_objects, pick_rigged, false, true, select_reflection_probes);
// Pass mousedown to agent
LLTool::handleMouseDown(x, y, mask);
@@ -73,7 +73,6 @@ bool LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask)
return mPick.getObject().notNull();
}
-
// static
LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pick, bool ignore_group, bool temp_select, bool select_root)
{
diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp
index beae71e7bf..44eb8461f1 100644
--- a/indra/newview/lluilistener.cpp
+++ b/indra/newview/lluilistener.cpp
@@ -34,55 +34,195 @@
// std headers
// external library headers
// other Linden headers
+#include "llmenugl.h"
+#include "lltoolbarview.h"
#include "llui.h" // getRootView(), resolvePath()
#include "lluictrl.h"
#include "llerror.h"
+#include "llviewermenufile.h" // close_all_windows()
+extern LLMenuBarGL* gMenuBarView;
+
+#define THROTTLE_PERIOD 1.5 // required seconds between throttled functions
+#define MIN_THROTTLE 0.5
LLUIListener::LLUIListener():
LLEventAPI("UI",
- "LLUICtrl::CommitCallbackRegistry listener.\n"
- "Capable of invoking any function (with parameter) you can specify in XUI.")
+ "Operations to manipulate the viewer's user interface.")
{
add("call",
"Invoke the operation named by [\"function\"], passing [\"parameter\"],\n"
"as if from a user gesture on a menu -- or a button click.",
&LLUIListener::call,
- LLSD().with("function", LLSD()));
+ llsd::map("function", LLSD(), "reply", LLSD()));
+
+ add("callables",
+ "Return a list [\"callables\"] of dicts {name, access} of functions registered to\n"
+ "invoke with \"call\".\n"
+ "access has values \"allow\", \"block\" or \"throttle\".",
+ &LLUIListener::callables,
+ llsd::map("reply", LLSD::String()));
add("getValue",
"For the UI control identified by the path in [\"path\"], return the control's\n"
"current value as [\"value\"] reply.",
&LLUIListener::getValue,
- LLSDMap("path", LLSD())("reply", LLSD()));
+ llsd::map("path", LLSD(), "reply", LLSD()));
+
+ add("getTopMenus",
+ "List names of Top menus suitable for passing as \"parent_menu\"",
+ &LLUIListener::getTopMenus,
+ llsd::map("reply", LLSD::String()));
+
+ LLSD required_args = llsd::map("name", LLSD(), "label", LLSD(), "reply", LLSD());
+ add("addMenu",
+ "Add new drop-down menu [\"name\"] with displayed [\"label\"] to the Top menu.",
+ &LLUIListener::addMenu,
+ required_args);
+
+ required_args.insert("parent_menu", LLSD());
+ add("addMenuBranch",
+ "Add new menu branch [\"name\"] with displayed [\"label\"]\n"
+ "to the [\"parent_menu\"] within the Top menu.",
+ &LLUIListener::addMenuBranch,
+ required_args);
+
+ add("addMenuItem",
+ "Add new menu item [\"name\"] with displayed [\"label\"]\n"
+ "and call-on-click UI function [\"func\"] with optional [\"param\"]\n"
+ "to the [\"parent_menu\"] within the Top menu.\n"
+ "If [\"pos\"] is present, insert at specified 0-relative position.",
+ &LLUIListener::addMenuItem,
+ required_args.with("func", LLSD()));
+
+ add("addMenuSeparator",
+ "Add menu separator to the [\"parent_menu\"] within the Top menu.\n"
+ "If [\"pos\"] is present, insert at specified 0-relative position.",
+ &LLUIListener::addMenuSeparator,
+ llsd::map("parent_menu", LLSD(), "reply", LLSD()));
+
+ add("setMenuVisible",
+ "Set menu [\"name\"] visibility to [\"visible\"]",
+ &LLUIListener::setMenuVisible,
+ llsd::map("name", LLSD(), "visible", LLSD(), "reply", LLSD()));
+
+ add("defaultToolbars",
+ "Restore default toolbar buttons",
+ &LLUIListener::restoreDefaultToolbars);
+
+ add("clearAllToolbars",
+ "Clear all buttons off the toolbars",
+ &LLUIListener::clearAllToolbars);
+
+ add("addToolbarBtn",
+ "Add [\"btn_name\"] toolbar button to the [\"toolbar\"]:\n"
+ "\"left\", \"right\", \"bottom\" (default is \"bottom\")\n"
+ "Position of the command in the original list can be specified as [\"rank\"],\n"
+ "where 0 means the first item",
+ &LLUIListener::addToolbarBtn,
+ llsd::map("btn_name", LLSD(), "reply", LLSD()));
+
+ add("removeToolbarBtn",
+ "Remove [\"btn_name\"] toolbar button off the toolbar,\n"
+ "return [\"rank\"] (old position) of the command in the original list,\n"
+ "rank 0 is the first position,\n"
+ "rank -1 means that [\"btn_name\"] was not found",
+ &LLUIListener::removeToolbarBtn,
+ llsd::map("btn_name", LLSD(), "reply", LLSD()));
+
+ add("getToolbarBtnNames",
+ "Return the table of Toolbar buttons names",
+ &LLUIListener::getToolbarBtnNames,
+ llsd::map("reply", LLSD()));
+
+ add("closeAllFloaters",
+ "Close all the floaters",
+ &LLUIListener::closeAllFloaters);
}
-void LLUIListener::call(const LLSD& event) const
+typedef LLUICtrl::CommitCallbackInfo cb_info;
+void LLUIListener::call(const LLSD& event)
{
- LLUICtrl::commit_callback_t* func =
- LLUICtrl::CommitCallbackRegistry::getValue(event["function"]);
- if (! func)
+ Response response(LLSD(), event);
+ cb_info *info = LLUICtrl::CommitCallbackRegistry::getValue(event["function"]);
+ if (!info || !info->callback_func)
+ {
+ return response.error(stringize("Function ", std::quoted(event["function"].asString()), " was not found"));
+ }
+ if (info->handle_untrusted == cb_info::UNTRUSTED_BLOCK)
+ {
+ return response.error(stringize("Function ", std::quoted(event["function"].asString()), " may not be called from the script"));
+ }
+
+ //Separate UNTRUSTED_THROTTLE and UNTRUSTED_ALLOW functions to have different timeout
+ F64 *throttlep, period;
+ if (info->handle_untrusted == cb_info::UNTRUSTED_THROTTLE)
{
- // This API is intended for use by a script. It's a fire-and-forget
- // API: we provide no reply. Therefore, a typo in the script will
- // provide no feedback whatsoever to that script. To rub the coder's
- // nose in such an error, crump rather than quietly ignoring it.
- LL_ERRS("LLUIListener") << "function '" << event["function"] << "' not found" << LL_ENDL;
+ throttlep = &mLastUntrustedThrottle;
+ period = THROTTLE_PERIOD;
}
else
{
- // Interestingly, view_listener_t::addMenu() (addCommit(),
- // addEnable()) constructs a commit_callback_t callable that accepts
- // two parameters but discards the first. Only the second is passed to
- // handleEvent(). Therefore we feel completely safe passing NULL for
- // the first parameter.
- (*func)(NULL, event["parameter"]);
+ throttlep = &mLastMinThrottle;
+ period = MIN_THROTTLE;
+ }
+
+ F64 cur_time = LLTimer::getElapsedSeconds();
+ F64 time_delta = *throttlep + period;
+ if (cur_time < time_delta)
+ {
+ LL_WARNS("LLUIListener") << "Throttled function " << std::quoted(event["function"].asString()) << LL_ENDL;
+ return;
}
+ *throttlep = cur_time;
+
+ // Interestingly, view_listener_t::addMenu() (addCommit(),
+ // addEnable()) constructs a commit_callback_t callable that accepts
+ // two parameters but discards the first. Only the second is passed to
+ // handleEvent(). Therefore we feel completely safe passing NULL for
+ // the first parameter.
+ (info->callback_func)(NULL, event["parameter"]);
}
-void LLUIListener::getValue(const LLSD&event) const
+void LLUIListener::callables(const LLSD& event) const
{
- LLSD reply = LLSD::emptyMap();
+ Response response(LLSD(), event);
+
+ using Registry = LLUICtrl::CommitCallbackRegistry;
+ using Method = Registry::Registrar& (*)();
+ static Method registrars[] =
+ {
+ &Registry::defaultRegistrar,
+ &Registry::currentRegistrar,
+ };
+ LLSD list;
+ for (auto method : registrars)
+ {
+ auto& registrar{ (*method)() };
+ for (auto it = registrar.beginItems(), end = registrar.endItems(); it != end; ++it)
+ {
+ LLSD entry{ llsd::map("name", it->first) };
+ switch (it->second.handle_untrusted)
+ {
+ case cb_info::UNTRUSTED_ALLOW:
+ entry["access"] = "allow";
+ break;
+ case cb_info::UNTRUSTED_BLOCK:
+ entry["access"] = "block";
+ break;
+ case cb_info::UNTRUSTED_THROTTLE:
+ entry["access"] = "throttle";
+ break;
+ }
+ list.append(entry);
+ }
+ }
+ response["callables"] = list;
+}
+
+void LLUIListener::getValue(const LLSD& event) const
+{
+ Response response(LLSD(), event);
const LLView* root = LLUI::getInstance()->getRootView();
const LLView* view = LLUI::getInstance()->resolvePath(root, event["path"].asString());
@@ -90,12 +230,192 @@ void LLUIListener::getValue(const LLSD&event) const
if (ctrl)
{
- reply["value"] = ctrl->getValue();
+ response["value"] = ctrl->getValue();
}
else
{
- // *TODO: ??? return something indicating failure to resolve
+ response.error(stringize("UI control ", std::quoted(event["path"].asString()), " was not found"));
+ }
+}
+
+void LLUIListener::getTopMenus(const LLSD& event) const
+{
+ Response response(LLSD(), event);
+ response["menus"] = llsd::toArray(
+ *gMenuBarView->getChildList(),
+ [](auto childp) {return childp->getName(); });
+}
+
+LLMenuGL::Params get_params(const LLSD&event)
+{
+ LLMenuGL::Params item_params;
+ item_params.name = event["name"];
+ item_params.label = event["label"];
+ item_params.can_tear_off = true;
+ return item_params;
+}
+
+LLMenuGL* get_parent_menu(LLEventAPI::Response& response, const LLSD&event)
+{
+ auto parent_menu_name{ event["parent_menu"].asString() };
+ LLMenuGL* parent_menu = gMenuBarView->findChildMenuByName(parent_menu_name, true);
+ if(!parent_menu)
+ {
+ response.error(stringize("Parent menu ", std::quoted(parent_menu_name), " was not found"));
+ }
+ return parent_menu;
+}
+
+// Return event["pos"].asInteger() if passed, but clamp (0 <= pos <= size).
+// Reserve -1 return to mean event has no "pos" key.
+S32 get_pos(const LLSD& event, U32 size)
+{
+ return event["pos"].isInteger()? llclamp(event["pos"].asInteger(), 0, size) : -1;
+}
+
+void LLUIListener::addMenu(const LLSD&event) const
+{
+ Response response(LLSD(), event);
+ LLMenuGL::Params item_params = get_params(event);
+ if(!gMenuBarView->appendMenu(LLUICtrlFactory::create<LLMenuGL>(item_params)))
+ {
+ response.error(stringize("Menu ", std::quoted(event["name"].asString()), " was not added"));
+ }
+}
+
+void LLUIListener::addMenuBranch(const LLSD&event) const
+{
+ Response response(LLSD(), event);
+ if(LLMenuGL* parent_menu = get_parent_menu(response, event))
+ {
+ LLMenuGL::Params item_params = get_params(event);
+ if(!parent_menu->appendMenu(LLUICtrlFactory::create<LLMenuGL>(item_params)))
+ {
+ response.error(stringize("Menu branch ", std::quoted(event["name"].asString()), " was not added"));
+ }
+ }
+}
+
+void LLUIListener::addMenuItem(const LLSD&event) const
+{
+ Response response(LLSD(), event);
+ LLMenuItemCallGL::Params item_params;
+ item_params.name = event["name"];
+ item_params.label = event["label"];
+ LLUICtrl::CommitCallbackParam item_func;
+ item_func.function_name = event["func"];
+ if (event.has("param"))
+ {
+ item_func.parameter = event["param"];
}
+ item_params.on_click = item_func;
+ if(LLMenuGL* parent_menu = get_parent_menu(response, event))
+ {
+ auto item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
+ // Clamp pos to getItemCount(), meaning append. If pos exceeds that,
+ // insert() will silently ignore the request.
+ auto pos = get_pos(event, parent_menu->getItemCount());
+ if (pos >= 0)
+ {
+ // insert() returns void: we just have to assume it worked.
+ parent_menu->insert(pos, item);
+ }
+ else if (! parent_menu->append(item))
+ {
+ response.error(stringize("Menu item ", std::quoted(event["name"].asString()),
+ " was not added"));
+ }
+ }
+}
+
+void LLUIListener::addMenuSeparator(const LLSD&event) const
+{
+ Response response(LLSD(), event);
+ if(LLMenuGL* parent_menu = get_parent_menu(response, event))
+ {
+ // Clamp pos to getItemCount(), meaning append. If pos exceeds that,
+ // insert() will silently ignore the request.
+ auto pos = get_pos(event, parent_menu->getItemCount());
+ if (pos >= 0)
+ {
+ // Even though addSeparator() does not accept a position,
+ // LLMenuItemSeparatorGL isa LLMenuItemGL, so we can use insert().
+ LLMenuItemSeparatorGL::Params p;
+ LLMenuItemGL* separator = LLUICtrlFactory::create<LLMenuItemSeparatorGL>(p);
+ // insert() returns void: we just have to assume it worked.
+ parent_menu->insert(pos, separator);
+ }
+ else if (! parent_menu->addSeparator())
+ {
+ response.error("Separator was not added");
+ }
+ }
+}
- sendReply(reply, event);
+void LLUIListener::setMenuVisible(const LLSD &event) const
+{
+ Response response(LLSD(), event);
+ std::string menu_name(event["name"]);
+ if (!gMenuBarView->getItem(menu_name))
+ {
+ return response.error(stringize("Menu ", std::quoted(menu_name), " was not found"));
+ }
+ gMenuBarView->setItemVisible(menu_name, event["visible"].asBoolean());
+}
+
+void LLUIListener::restoreDefaultToolbars(const LLSD &event) const
+{
+ LLToolBarView::loadDefaultToolbars();
+}
+
+void LLUIListener::clearAllToolbars(const LLSD &event) const
+{
+ LLToolBarView::clearAllToolbars();
+}
+
+void LLUIListener::addToolbarBtn(const LLSD &event) const
+{
+ Response response(LLSD(), event);
+
+ typedef LLToolBarEnums::EToolBarLocation ToolBarLocation;
+ ToolBarLocation toolbar = ToolBarLocation::TOOLBAR_BOTTOM;
+ if (event.has("toolbar"))
+ {
+ if (event["toolbar"] == "left")
+ {
+ toolbar = ToolBarLocation::TOOLBAR_LEFT;
+ }
+ else if (event["toolbar"] == "right")
+ {
+ toolbar = ToolBarLocation::TOOLBAR_RIGHT;
+ }
+ else if (event["toolbar"] != "bottom")
+ {
+ return response.error(stringize("Toolbar name ", std::quoted(event["toolbar"].asString()), " is not correct. Toolbar names are: left, right, bottom"));
+ }
+ }
+ S32 rank = event.has("rank") ? event["rank"].asInteger() : LLToolBar::RANK_NONE;
+ if(!gToolBarView->addCommand(event["btn_name"].asString(), toolbar, rank))
+ {
+ response.error(stringize("Toolbar button ", std::quoted(event["btn_name"].asString()), " was not found"));
+ }
+}
+
+void LLUIListener::removeToolbarBtn(const LLSD &event) const
+{
+ Response response(LLSD(), event);
+
+ S32 old_rank = LLToolBar::RANK_NONE;
+ gToolBarView->removeCommand(event["btn_name"].asString(), old_rank);
+ response["rank"] = old_rank;
+}
+
+void LLUIListener::getToolbarBtnNames(const LLSD &event) const
+{
+ Response response(llsd::map("cmd_names", LLCommandManager::instance().getCommandNames()), event);
+}
+
+void LLUIListener::closeAllFloaters(const LLSD &event) const
+{
+ close_all_windows();
}
diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h
index 70455c2c68..8fc8e6ebb4 100644
--- a/indra/newview/lluilistener.h
+++ b/indra/newview/lluilistener.h
@@ -40,8 +40,27 @@ public:
LLUIListener();
private:
- void call(const LLSD& event) const;
- void getValue(const LLSD&event) const;
+ void call(const LLSD& event);
+ void callables(const LLSD& event) const;
+ void getValue(const LLSD& event) const;
+ void getTopMenus(const LLSD& event) const;
+
+ void addMenu(const LLSD&event) const;
+ void addMenuBranch(const LLSD&event) const;
+ void addMenuItem(const LLSD&event) const;
+ void addMenuSeparator(const LLSD&event) const;
+ void setMenuVisible(const LLSD &event) const;
+
+ void restoreDefaultToolbars(const LLSD &event) const;
+ void clearAllToolbars(const LLSD &event) const;
+ void addToolbarBtn(const LLSD &event) const;
+ void removeToolbarBtn(const LLSD &event) const;
+ void getToolbarBtnNames(const LLSD &event) const;
+
+ void closeAllFloaters(const LLSD &event) const;
+
+ F64 mLastUntrustedThrottle {0};
+ F64 mLastMinThrottle {0};
};
#endif /* ! defined(LL_LLUILISTENER_H) */
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
index 39a9f0f8bc..647210b7e6 100644
--- a/indra/newview/llurldispatcher.cpp
+++ b/indra/newview/llurldispatcher.cpp
@@ -289,6 +289,8 @@ public:
LLEventAPI::add("teleport",
"Teleport to specified [\"regionname\"] at\n"
"specified region-relative [\"x\"], [\"y\"], [\"z\"].\n"
+ "If [\"regionname\"] is \"home\", ignore [\"x\"], [\"y\"], [\"z\"]\n"
+ "and teleport home.\n"
"If [\"regionname\"] omitted, teleport to GLOBAL\n"
"coordinates [\"x\"], [\"y\"], [\"z\"].",
&LLTeleportHandler::from_event);
@@ -304,7 +306,7 @@ public:
if (tokens.size() < 1) return false;
LLVector3 coords(128, 128, 0);
- if (tokens.size() <= 4)
+ if (tokens.size() >= 3) // Require at least [1] and [2]
{
coords = LLVector3((F32)tokens[1].asReal(),
(F32)tokens[2].asReal(),
@@ -328,7 +330,12 @@ public:
void from_event(const LLSD& params) const
{
Response response(LLSD(), params);
- if (params.has("regionname"))
+ if (params["regionname"].asString() == "home")
+ {
+ gAgent.teleportHome();
+ response["message"] = "Teleporting home";
+ }
+ else if (params.has("regionname"))
{
// region specified, coordinates (if any) are region-local
LLVector3 local_pos(
diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp
index 7ef2c8d697..07921e472c 100644
--- a/indra/newview/llviewerassetupload.cpp
+++ b/indra/newview/llviewerassetupload.cpp
@@ -62,7 +62,8 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
LLAssetType::EType assetType, std::string name, std::string description,
S32 compressionInfo, LLFolderType::EType destinationType,
LLInventoryType::EType inventoryType, U32 nextOWnerPerms,
- U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) :
+ U32 groupPerms, U32 everyonePerms, S32 expectedCost,
+ const LLUUID& destFolderId, bool showInventory) :
mTransactionId(transactId),
mAssetType(assetType),
mName(name),
@@ -75,7 +76,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
mEveryonePerms(everyonePerms),
mExpectedUploadCost(expectedCost),
mShowInventory(showInventory),
- mFolderId(LLUUID::null),
+ mFolderId(destFolderId),
mItemId(LLUUID::null),
mAssetId(LLAssetID::null)
{ }
@@ -84,7 +85,8 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
LLResourceUploadInfo::LLResourceUploadInfo(std::string name,
std::string description, S32 compressionInfo,
LLFolderType::EType destinationType, LLInventoryType::EType inventoryType,
- U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) :
+ U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost,
+ const LLUUID& destFolderId, bool showInventory) :
mName(name),
mDescription(description),
mCompressionInfo(compressionInfo),
@@ -97,7 +99,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(std::string name,
mShowInventory(showInventory),
mTransactionId(),
mAssetType(LLAssetType::AT_NONE),
- mFolderId(LLUUID::null),
+ mFolderId(destFolderId),
mItemId(LLUUID::null),
mAssetId(LLAssetID::null)
{
@@ -299,17 +301,20 @@ void LLResourceUploadInfo::assignDefaults()
mDescription = "(No Description)";
}
- if (mAssetType == LLAssetType::AT_GLTF ||
- mAssetType == LLAssetType::AT_GLTF_BIN)
+ if (mFolderId.isNull())
{
- mFolderId = LLUUID::null;
+ if (mAssetType == LLAssetType::AT_GLTF ||
+ mAssetType == LLAssetType::AT_GLTF_BIN)
+ {
+ mFolderId = LLUUID::null;
+ }
+ else
+ {
+ mFolderId = gInventory.findUserDefinedCategoryUUIDForType(
+ (mDestinationFolderType == LLFolderType::FT_NONE) ?
+ (LLFolderType::EType)mAssetType : mDestinationFolderType);
+ }
}
- else
- {
- mFolderId = gInventory.findUserDefinedCategoryUUIDForType(
- (mDestinationFolderType == LLFolderType::FT_NONE) ?
- (LLFolderType::EType)mAssetType : mDestinationFolderType);
-}
}
std::string LLResourceUploadInfo::getDisplayName() const
@@ -366,10 +371,12 @@ LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo(
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
+ const LLUUID& destFolderId,
bool show_inventory) :
LLResourceUploadInfo(name, description, compressionInfo,
destinationType, inventoryType,
- nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory),
+ nextOWnerPerms, groupPerms, everyonePerms, expectedCost,
+ destFolderId, show_inventory),
mFileName(fileName),
mMaxImageSize(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT)
{
@@ -580,12 +587,13 @@ LLNewBufferedResourceUploadInfo::LLNewBufferedResourceUploadInfo(
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
+ const LLUUID& destFolderId,
bool show_inventory,
uploadFinish_f finish,
uploadFailure_f failure)
: LLResourceUploadInfo(name, description, compressionInfo,
destinationType, inventoryType,
- nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory)
+ nextOWnerPerms, groupPerms, everyonePerms, expectedCost, destFolderId, show_inventory)
, mBuffer(buffer)
, mFinishFn(finish)
, mFailureFn(failure)
diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h
index 365436ede0..3e168fd879 100644
--- a/indra/newview/llviewerassetupload.h
+++ b/indra/newview/llviewerassetupload.h
@@ -54,6 +54,7 @@ public:
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
+ const LLUUID& destFolderId = LLUUID::null,
bool showInventory = true);
virtual ~LLResourceUploadInfo()
@@ -104,6 +105,7 @@ protected:
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
+ const LLUUID& destFolderId = LLUUID::null,
bool showInventory = true);
LLResourceUploadInfo(
@@ -155,6 +157,7 @@ public:
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
+ const LLUUID& destFolderId = LLUUID::null,
bool show_inventory = true);
virtual LLSD prepareUpload();
@@ -193,6 +196,7 @@ public:
U32 groupPerms,
U32 everyonePerms,
S32 expectedCost,
+ const LLUUID& destFolderId, // use null for default
bool show_inventory,
uploadFinish_f finish,
uploadFailure_f failure);
@@ -219,6 +223,7 @@ public:
typedef std::function<void(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response)> taskUploadFinish_f;
typedef std::function<bool(LLUUID itemId, LLUUID taskId, LLSD response, std::string reason)> uploadFailed_f;
+ // destFolderId is the folder to put the new item in, leave null for default
LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish, uploadFailed_f failed);
LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LLImageFormatted> image, invnUploadFinish_f finish);
LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemId, LLAssetType::EType assetType, std::string buffer, taskUploadFinish_f finish, uploadFailed_f failed);
diff --git a/indra/newview/llviewerattachmenu.cpp b/indra/newview/llviewerattachmenu.cpp
index f2557e299c..9828ab1fdf 100644
--- a/indra/newview/llviewerattachmenu.cpp
+++ b/indra/newview/llviewerattachmenu.cpp
@@ -116,12 +116,12 @@ void LLViewerAttachMenu::attachObjects(const uuid_vec_t& items, const std::strin
LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getLinkedItem(id);
if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()))
{
- rez_attachment(item, attachmentp); // don't replace if called from an "Attach To..." menu
+ rez_attachment(item, attachmentp, false); // don't replace if called from an "Attach To..." menu
}
else if(item && item->isFinished())
{
// must be in library. copy it to our inventory and put it on.
- LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp));
+ LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp, false));
copy_inventory_item(gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index f5acc840be..048f316dc8 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -81,18 +81,16 @@ LLViewerCamera::~LLViewerCamera()
mCameraAngleChangedSignal.disconnect();
}
-void LLViewerCamera::updateCameraLocation(const LLVector3 &center, const LLVector3 &up_direction, const LLVector3 &point_of_interest)
+bool LLViewerCamera::updateCameraLocation(const LLVector3 &center, const LLVector3 &up_direction, const LLVector3 &point_of_interest)
{
// do not update if avatar didn't move
if (!LLViewerJoystick::getInstance()->getCameraNeedsUpdate())
{
- return;
+ return true;
}
- LLVector3 last_position;
- LLVector3 last_axis;
- last_position = getOrigin();
- last_axis = getAtAxis();
+ LLVector3 last_position = getOrigin();
+ LLVector3 last_axis = getAtAxis();
mLastPointOfInterest = point_of_interest;
@@ -102,30 +100,49 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center, const LLVecto
regp = gAgent.getRegion();
}
- F32 water_height = (NULL != regp) ? regp->getWaterHeight() : 0.f;
+ F32 water_height = regp ? regp->getWaterHeight() : 0.f;
LLVector3 origin = center;
+ // Move origin[VZ] far enough (up or down) from the water surface
+ static const F32 MIN_DIST_TO_WATER = 0.2f;
+ F32& zpos = origin.mV[VZ];
+ if (zpos < water_height + MIN_DIST_TO_WATER)
{
- if (origin.mV[2] > water_height)
+ if (zpos >= water_height)
{
- origin.mV[2] = llmax(origin.mV[2], water_height + 0.20f);
+ zpos = water_height + MIN_DIST_TO_WATER;
}
- else
+ else if (zpos > water_height - MIN_DIST_TO_WATER)
{
- origin.mV[2] = llmin(origin.mV[2], water_height - 0.20f);
+ zpos = water_height - MIN_DIST_TO_WATER;
}
}
- setOriginAndLookAt(origin, up_direction, point_of_interest);
+ LLVector3 at(point_of_interest - origin);
+ at.normalize();
+ if (at.isNull() || !at.isFinite())
+ return false;
+
+ LLVector3 left(up_direction % at);
+ left.normalize();
+ if (left.isNull() || !left.isFinite())
+ return false;
+
+ LLVector3 up = at % left;
+ up.normalize();
+ if (up.isNull() || !up.isFinite())
+ return false;
+
+ setOrigin(origin);
+ setAxes(at, left, up);
- mVelocityDir = origin - last_position ;
- F32 dpos = mVelocityDir.normVec() ;
+ mVelocityDir = origin - last_position;
+ F32 dpos = mVelocityDir.normVec();
LLQuaternion rotation;
rotation.shortestArc(last_axis, getAtAxis());
- F32 x, y, z;
- F32 drot;
+ F32 drot, x, y, z;
rotation.getAngleAxis(&drot, &x, &y, &z);
add(sVelocityStat, dpos);
@@ -138,14 +155,15 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center, const LLVecto
// update pixel meter ratio using default fov, not modified one
mPixelMeterRatio = (F32)(getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5f)));
// update screen pixel area
- mScreenPixelArea =(S32)((F32)getViewHeightInPixels() * ((F32)getViewHeightInPixels() * getAspect()));
+ mScreenPixelArea = (S32)((F32)getViewHeightInPixels() * ((F32)getViewHeightInPixels() * getAspect()));
+
+ return true;
}
const LLMatrix4 &LLViewerCamera::getProjection() const
{
calcProjection(getFar());
return mProjectionMatrix;
-
}
const LLMatrix4 &LLViewerCamera::getModelview() const
@@ -158,19 +176,18 @@ const LLMatrix4 &LLViewerCamera::getModelview() const
void LLViewerCamera::calcProjection(const F32 far_distance) const
{
- F32 fov_y, z_far, z_near, aspect, f;
- fov_y = getView();
- z_far = far_distance;
- z_near = getNear();
- aspect = getAspect();
+ F32 fov_y = getView();
+ F32 z_far = far_distance;
+ F32 z_near = getNear();
+ F32 aspect = getAspect();
- f = 1/tan(fov_y*0.5f);
+ F32 f = 1 / tan(fov_y * 0.5f);
mProjectionMatrix.setZero();
- mProjectionMatrix.mMatrix[0][0] = f/aspect;
+ mProjectionMatrix.mMatrix[0][0] = f / aspect;
mProjectionMatrix.mMatrix[1][1] = f;
- mProjectionMatrix.mMatrix[2][2] = (z_far + z_near)/(z_near - z_far);
- mProjectionMatrix.mMatrix[3][2] = (2*z_far*z_near)/(z_near - z_far);
+ mProjectionMatrix.mMatrix[2][2] = (z_far + z_near) / (z_near - z_far);
+ mProjectionMatrix.mMatrix[3][2] = (2 * z_far * z_near) / (z_near - z_far);
mProjectionMatrix.mMatrix[2][3] = -1;
}
@@ -231,9 +248,9 @@ void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, bool ortho, bool zfli
for (U32 i = 0; i < 4; i++)
{
- frust[i+4] = frust[i+4]-frust[i];
- frust[i+4].normVec();
- frust[i+4] = frust[i] + frust[i+4]*camera.getFar();
+ frust[i + 4] = frust[i + 4] - frust[i];
+ frust[i + 4].normVec();
+ frust[i + 4] = frust[i] + frust[i + 4] * camera.getFar();
}
}
else
@@ -249,7 +266,7 @@ void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, bool ortho, bool zfli
if (ortho)
{
- LLVector3 far_shift = camera.getAtAxis()*camera.getFar()*2.f;
+ LLVector3 far_shift = camera.getAtAxis() * camera.getFar() * 2.f;
for (U32 i = 0; i < 4; i++)
{
frust[i+4] = frust[i] + far_shift;
@@ -261,7 +278,7 @@ void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, bool ortho, bool zfli
{
LLVector3 vec = frust[i] - camera.getOrigin();
vec.normVec();
- frust[i+4] = camera.getOrigin() + vec*camera.getFar();
+ frust[i + 4] = camera.getOrigin() + vec * camera.getFar();
}
}
}
@@ -357,7 +374,7 @@ void LLViewerCamera::setPerspective(bool for_selection,
glm::mat4 modelview(glm::make_mat4((GLfloat*) OGL_TO_CFR_ROTATION));
- GLfloat ogl_matrix[16];
+ GLfloat ogl_matrix[16];
getOpenGLTransform(ogl_matrix);
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index a204b85d88..c1c73dc0c6 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -61,7 +61,7 @@ public:
static eCameraID sCurCameraID;
- void updateCameraLocation(const LLVector3 &center,
+ bool updateCameraLocation(const LLVector3 &center,
const LLVector3 &up_direction,
const LLVector3 &point_of_interest);
@@ -77,12 +77,12 @@ public:
bool projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const bool clamp = true) const;
bool projectPosAgentToScreenEdge(const LLVector3 &pos_agent, LLCoordGL &out_point) const;
- LLVector3 getVelocityDir() const {return mVelocityDir;}
- static LLTrace::CountStatHandle<>* getVelocityStat() {return &sVelocityStat; }
- static LLTrace::CountStatHandle<>* getAngularVelocityStat() {return &sAngularVelocityStat; }
- F32 getCosHalfFov() {return mCosHalfCameraFOV;}
- F32 getAverageSpeed() {return mAverageSpeed ;}
- F32 getAverageAngularSpeed() {return mAverageAngularSpeed;}
+ LLVector3 getVelocityDir() const { return mVelocityDir; }
+ static LLTrace::CountStatHandle<>* getVelocityStat() { return &sVelocityStat; }
+ static LLTrace::CountStatHandle<>* getAngularVelocityStat() { return &sAngularVelocityStat; }
+ F32 getCosHalfFov() const { return mCosHalfCameraFOV; }
+ F32 getAverageSpeed() const { return mAverageSpeed; }
+ F32 getAverageAngularSpeed() const { return mAverageAngularSpeed; }
void getPixelVectors(const LLVector3 &pos_agent, LLVector3 &up, LLVector3 &right);
LLVector3 roundToPixel(const LLVector3 &pos_agent);
@@ -90,21 +90,21 @@ public:
// Sets the current matrix
/* virtual */ void setView(F32 vertical_fov_rads); // NOTE: broadcasts to simulator
void setViewNoBroadcast(F32 vertical_fov_rads); // set FOV without broadcasting to simulator (for temporary local cameras)
- void setDefaultFOV(F32 fov) ;
- F32 getDefaultFOV() { return mCameraFOVDefault; }
+ void setDefaultFOV(F32 fov);
+ F32 getDefaultFOV() const { return mCameraFOVDefault; }
bool isDefaultFOVChanged();
bool cameraUnderWater() const;
bool areVertsVisible(LLViewerObject* volumep, bool all_verts);
- const LLVector3 &getPointOfInterest() { return mLastPointOfInterest; }
+ const LLVector3& getPointOfInterest() const { return mLastPointOfInterest; }
F32 getPixelMeterRatio() const { return mPixelMeterRatio; }
S32 getScreenPixelArea() const { return mScreenPixelArea; }
void setZoomParameters(F32 factor, S16 subregion) { mZoomFactor = factor; mZoomSubregion = subregion; }
- F32 getZoomFactor() { return mZoomFactor; }
- S16 getZoomSubRegion() { return mZoomSubregion; }
+ F32 getZoomFactor() const { return mZoomFactor; }
+ S16 getZoomSubRegion() const { return mZoomSubregion; }
protected:
void calcProjection(const F32 far_distance) const;
diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp
index 8b01c4ef88..5daccb6784 100644
--- a/indra/newview/llviewerchat.cpp
+++ b/indra/newview/llviewerchat.cpp
@@ -30,6 +30,7 @@
// newview includes
#include "llagent.h" // gAgent
#include "llslurl.h"
+#include "lltrans.h"
#include "lluicolor.h"
#include "lluicolortable.h"
#include "llviewercontrol.h" // gSavedSettings
@@ -220,8 +221,7 @@ S32 LLViewerChat::getChatFontSize()
//static
void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg)
{
- std::string tmpmsg = chat.mText;
-
+ std::string tmpmsg = without_LUA_PREFIX(chat.mText, chat.mIsScript);
if(chat.mChatStyle == CHAT_STYLE_IRC)
{
formated_msg = chat.mFromName + tmpmsg.substr(3);
@@ -231,6 +231,11 @@ void LLViewerChat::formatChatMsg(const LLChat& chat, std::string& formated_msg)
formated_msg = tmpmsg;
}
+ if (chat.mIsScript)
+ {
+ formated_msg = LLTrans::getString("ScriptStr") + formated_msg;
+ }
+
}
//static
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 865d7fd442..184c0e7d8b 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -76,6 +76,7 @@
#include "llslurl.h"
#include "llstartup.h"
#include "llperfstats.h"
+#include "rlvcommon.h"
// Third party library includes
#include <boost/algorithm/string.hpp>
@@ -910,6 +911,7 @@ void settings_setup_listeners()
setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged);
setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged);
{
+ setting_setup_signal_listener(gSavedSettings, "LocalTerrainPaintEnabled", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "LocalTerrainPaintEnabled", handleLocalTerrainChanged);
const char* transform_suffixes[] = {
"ScaleU",
@@ -932,6 +934,8 @@ void settings_setup_listeners()
setting_setup_signal_listener(gSavedSettings, "TerrainPaintBitDepth", handleSetShaderChanged);
setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged);
+
+ setting_setup_signal_listener(gSavedSettings, Rlv::Settings::TopLevelMenu, Rlv::Util::menuToggleVisible);
}
#if TEST_CACHED_CONTROL
diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp
index 6f77e21fcc..4e39b03903 100644
--- a/indra/newview/llviewercontrollistener.cpp
+++ b/indra/newview/llviewercontrollistener.cpp
@@ -141,7 +141,8 @@ void LLViewerControlListener::set(LLSD const & request)
if (request.has("value"))
{
- info.control->setValue(request["value"]);
+ LL_WARNS("LLViewerControlListener") << "Changing debug setting " << std::quoted(info.key) << " to " << request["value"] << LL_ENDL;
+ info.control->setValue(request["value"], false);
}
else
{
@@ -158,7 +159,9 @@ void LLViewerControlListener::toggle(LLSD const & request)
if (info.control->isType(TYPE_BOOLEAN))
{
- info.control->set(! info.control->get().asBoolean());
+ bool value = !info.control->get().asBoolean();
+ LL_WARNS("LLViewerControlListener") << "Toggling debug setting " << std::quoted(info.key) << " to " << value << LL_ENDL;
+ info.control->set(value, false);
}
else
{
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 966abf3071..b5d0063cd8 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -55,7 +55,6 @@
#include "llmemory.h"
#include "llparcel.h"
#include "llperfstats.h"
-#include "llpostprocess.h"
#include "llrender.h"
#include "llscenemonitor.h"
#include "llsdjson.h"
@@ -80,6 +79,7 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewershadermgr.h"
+#include "llviewerstats.h"
#include "llviewertexturelist.h"
#include "llviewerwindow.h"
#include "llvoavatarself.h"
@@ -100,13 +100,13 @@
extern LLPointer<LLViewerTexture> gStartTexture;
extern bool gShiftFrame;
-LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
+LLPointer<LLViewerTexture> gDisconnectedImagep = nullptr;
// used to toggle renderer back on after teleport
bool gTeleportDisplay = false;
LLFrameTimer gTeleportDisplayTimer;
LLFrameTimer gTeleportArrivalTimer;
-const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
+constexpr F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
bool gForceRenderLandFence = false;
bool gDisplaySwapBuffers = false;
@@ -120,9 +120,9 @@ bool gSnapshotNoPost = false;
bool gShaderProfileFrame = false;
// This is how long the sim will try to teleport you before giving up.
-const F32 TELEPORT_EXPIRY = 15.0f;
+constexpr F32 TELEPORT_EXPIRY = 15.0f;
// Additional time (in seconds) to wait per attachment
-const F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f;
+constexpr F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f;
U32 gRecentFrameCount = 0; // number of 'recent' frames
LLFrameTimer gRecentFPSTime;
@@ -130,8 +130,6 @@ LLFrameTimer gRecentMemoryTime;
LLFrameTimer gAssetStorageLogTime;
// Rendering stuff
-void pre_show_depth_buffer();
-void post_show_depth_buffer();
void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
void swap();
void render_hud_attachments();
@@ -212,7 +210,8 @@ void display_update_camera()
F32 final_far = gAgentCamera.mDrawDistance;
if (gCubeSnapshot)
{
- final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance");
+ static LLCachedControl<F32> reflection_probe_draw_distance(gSavedSettings, "RenderReflectionProbeDrawDistance", 64.f);
+ final_far = reflection_probe_draw_distance();
}
else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
@@ -233,7 +232,7 @@ void display_update_camera()
void display_stats()
{
LL_PROFILE_ZONE_SCOPED;
- const F32 FPS_LOG_FREQUENCY = 10.f;
+ constexpr F32 FPS_LOG_FREQUENCY = 10.f;
if (gRecentFPSTime.getElapsedTimeF32() >= FPS_LOG_FREQUENCY)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS");
@@ -242,7 +241,7 @@ void display_stats()
gRecentFrameCount = 0;
gRecentFPSTime.reset();
}
- F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
+ static LLCachedControl<F32> mem_log_freq(gSavedSettings, "MemoryLogFrequency", 600.f);
if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory");
@@ -252,7 +251,7 @@ void display_stats()
LLMemory::logMemoryInfo(true) ;
gRecentMemoryTime.reset();
}
- const F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f;
+ constexpr F32 ASSET_STORAGE_LOG_FREQUENCY = 60.f;
if (gAssetStorageLogTime.getElapsedTimeF32() >= ASSET_STORAGE_LOG_FREQUENCY)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage");
@@ -539,8 +538,10 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
LLImageGL::updateStats(gFrameTimeSeconds);
- LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
- LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
+ static LLCachedControl<S32> avatar_name_tag_mode(gSavedSettings, "AvatarNameTagMode", 1);
+ static LLCachedControl<bool> name_tag_show_group_titles(gSavedSettings, "NameTagShowGroupTitles", true);
+ LLVOAvatar::sRenderName = avatar_name_tag_mode;
+ LLVOAvatar::sRenderGroupTitles = name_tag_show_group_titles && avatar_name_tag_mode > 0;
gPipeline.mBackfaceCull = true;
gFrameCount++;
@@ -763,7 +764,7 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
}
gGL.setColorMask(true, true);
- glClearColor(0,0,0,0);
+ glClearColor(0.f, 0.f, 0.f, 0.f);
LLGLState::checkStates();
@@ -933,7 +934,7 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
gPipeline.mRT->deferredScreen.bindTarget();
if (gUseWireframe)
{
- F32 g = 0.5f;
+ constexpr F32 g = 0.5f;
glClearColor(g, g, g, 1.f);
}
else
@@ -947,8 +948,8 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
gPipeline.mRT->screen.bindTarget();
if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders())
{
- const LLColor4 &col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();
- glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
+ const LLColor4& col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();
+ glClearColor(col.mV[VRED], col.mV[VGREEN], col.mV[VBLUE], 0.f);
}
gPipeline.mRT->screen.clear();
}
@@ -963,11 +964,12 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5")
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- if (gSavedSettings.getBOOL("RenderDepthPrePass"))
+ static LLCachedControl<bool> render_depth_pre_pass(gSavedSettings, "RenderDepthPrePass", false);
+ if (render_depth_pre_pass)
{
gGL.setColorMask(false, false);
- static const U32 types[] = {
+ constexpr U32 types[] = {
LLRenderPass::PASS_SIMPLE,
LLRenderPass::PASS_FULLBRIGHT,
LLRenderPass::PASS_SHINY
@@ -1084,6 +1086,9 @@ void getProfileStatsContext(boost::json::object& stats)
context.emplace("parcelid", parcel->getLocalID());
}
context.emplace("time", LLDate::now().toHTTPDateString("%Y-%m-%dT%H:%M:%S"));
+
+ // supplement with stats packet
+ stats.emplace("stats", LlsdToJson(capture_viewer_stats(true)));
}
std::string getProfileStatsFilename()
@@ -1181,7 +1186,7 @@ void display_cube_face()
gGL.setColorMask(true, true);
- glClearColor(0, 0, 0, 0);
+ glClearColor(0.f, 0.f, 0.f, 0.f);
gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
glClear(GL_DEPTH_BUFFER_BIT); // | GL_STENCIL_BUFFER_BIT);
@@ -1217,7 +1222,7 @@ void display_cube_face()
}
else
{
- glClearColor(1, 0, 1, 1);
+ glClearColor(1.f, 0.f, 1.f, 1.f);
}
gPipeline.mRT->deferredScreen.clear();
@@ -1258,11 +1263,12 @@ void render_hud_attachments()
{
LLPipeline::sRenderingHUDs = true;
LLCamera hud_cam = *LLViewerCamera::getInstance();
- hud_cam.setOrigin(-1.f,0,0);
- hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
+ hud_cam.setOrigin(-1.f, 0.f, 0.f);
+ hud_cam.setAxes(LLVector3(1.f, 0.f, 0.f), LLVector3(0.f, 1.f, 0.f), LLVector3(0.f, 0.f, 1.f));
LLViewerCamera::updateFrustumPlanes(hud_cam, true);
- bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
+ static LLCachedControl<bool> render_hud_particles(gSavedSettings, "RenderHUDParticles", false);
+ bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && render_hud_particles;
//only render hud objects
gPipeline.pushRenderTypeMask();
@@ -1622,10 +1628,11 @@ void render_ui_3d()
stop_glerror();
gUIProgram.bind();
- gGL.color4f(1, 1, 1, 1);
+ gGL.color4f(1.f, 1.f, 1.f, 1.f);
// Coordinate axes
- if (gSavedSettings.getBOOL("ShowAxes"))
+ static LLCachedControl<bool> show_axes(gSavedSettings, "ShowAxes");
+ if (show_axes())
{
draw_axes();
}
@@ -1687,7 +1694,7 @@ void render_ui_2d()
gGL.pushMatrix();
S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
- gGL.scalef(LLUI::getScaleFactor().mV[0], LLUI::getScaleFactor().mV[1], 1.f);
+ gGL.scalef(LLUI::getScaleFactor().mV[VX], LLUI::getScaleFactor().mV[VY], 1.f);
gGL.translatef((F32)half_width, (F32)half_height, 0.f);
F32 zoom = gAgentCamera.mHUDCurZoom;
gGL.scalef(zoom,zoom,1.f);
@@ -1709,7 +1716,7 @@ void render_ui_2d()
gPipeline.mUIScreen.bindTarget();
gGL.setColorMask(true, true);
{
- static const S32 pad = 8;
+ constexpr S32 pad = 8;
LLView::sDirtyRect.mLeft -= pad;
LLView::sDirtyRect.mRight += pad;
@@ -1762,8 +1769,6 @@ void render_ui_2d()
gViewerWindow->draw();
}
-
-
// reset current origin for font rendering, in case of tiling render
LLFontGL::sCurOrigin.set(0, 0);
}
@@ -1772,7 +1777,7 @@ void render_disconnected_background()
{
gUIProgram.bind();
- gGL.color4f(1,1,1,1);
+ gGL.color4f(1.f, 1.f, 1.f, 1.f);
if (!gDisconnectedImagep && gDisconnected)
{
LL_INFOS() << "Loading last bitmap..." << LL_ENDL;
@@ -1812,7 +1817,7 @@ void render_disconnected_background()
raw->expandToPowerOfTwo();
- gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), false );
+ gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), false);
gStartTexture = gDisconnectedImagep;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
@@ -1847,6 +1852,5 @@ void render_disconnected_background()
void display_cleanup()
{
- gDisconnectedImagep = NULL;
+ gDisconnectedImagep = nullptr;
}
-
diff --git a/indra/newview/llviewerdisplay.h b/indra/newview/llviewerdisplay.h
index 673f51600d..2ec02f09fd 100644
--- a/indra/newview/llviewerdisplay.h
+++ b/indra/newview/llviewerdisplay.h
@@ -27,8 +27,6 @@
#ifndef LL_LLVIEWERDISPLAY_H
#define LL_LLVIEWERDISPLAY_H
-class LLPostProcess;
-
void display_startup();
void display_cleanup();
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index c56b7073b7..87ebe22008 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -97,6 +97,8 @@
#include "llfloaterlandholdings.h"
#include "llfloaterlinkreplace.h"
#include "llfloaterloadprefpreset.h"
+#include "llfloaterluadebug.h"
+#include "llfloaterluascripts.h"
#include "llfloatermap.h"
#include "llfloatermarketplacelistings.h"
#include "llfloatermediasettings.h"
@@ -117,7 +119,6 @@
#include "llfloaterpay.h"
#include "llfloaterperformance.h"
#include "llfloaterperms.h"
-#include "llfloaterpostprocess.h"
#include "llfloaterpreference.h"
#include "llfloaterpreferencesgraphicsadvanced.h"
#include "llfloaterpreferenceviewadvanced.h"
@@ -176,6 +177,7 @@
#include "llpreviewtexture.h"
#include "llscriptfloater.h"
#include "llsyswellwindow.h"
+#include "rlvfloaters.h"
#include "fsfloatersearch.h"
@@ -364,7 +366,6 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiPicker>);
LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiComplete>);
- LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>);
LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>);
LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>);
@@ -418,6 +419,9 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("linkreplace", "floater_linkreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLinkReplace>);
LLFloaterReg::add("load_pref_preset", "floater_load_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLoadPrefPreset>);
+ LLFloaterReg::add("lua_debug", "floater_lua_debug.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUADebug>);
+ LLFloaterReg::add("lua_scripts", "floater_lua_scripts.xml", (LLFloaterBuildFunc) &LLFloaterReg::build<LLFloaterLUAScripts>);
+
LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>);
LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>);
@@ -486,6 +490,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>);
LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>);
LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>);
+ LLFloaterReg::add("rlv_console", "floater_rlv_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<Rlv::FloaterConsole>);
LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>);
LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>);
diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp
index ffcbd1b4d8..943a3b83bd 100644
--- a/indra/newview/llviewerinput.cpp
+++ b/indra/newview/llviewerinput.cpp
@@ -35,6 +35,7 @@
#include "llagentcamera.h"
#include "llfloaterimnearbychat.h"
#include "llfocusmgr.h"
+#include "llgamecontrol.h"
#include "llkeybind.h" // LLKeyData
#include "llmorphview.h"
#include "llmoveview.h"
@@ -160,9 +161,6 @@ static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode m
static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDoubleTapRunMode mode )
{
- agent_handle_doubletap_run(s, mode);
- if (KEYSTATE_UP == s) return;
-
F32 time = gKeyboard->getCurKeyElapsedTime();
S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount());
@@ -922,6 +920,20 @@ bool agent_control_lbutton_handle(EKeystate s)
return true;
}
+template <U8 N>
+bool game_control_button(EKeystate s)
+{
+ if (s == KEYSTATE_DOWN)
+ {
+ gAgent.pressGameControlButton(N);
+ }
+ else if ( s == KEYSTATE_UP)
+ {
+ gAgent.releaseGameControlButton(N);
+ }
+ return true;
+}
+
// In-world keybindings, like walking or camera
#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, LLKeybindFunctionData(ACTION, false));
// Global keybindings that should work even with floaters focused, like voice
@@ -979,6 +991,38 @@ REGISTER_KEYBOARD_ACTION("walk_to", walk_to);
REGISTER_KEYBOARD_GLOBAL_ACTION("toggle_voice", toggle_voice);
REGISTER_KEYBOARD_GLOBAL_ACTION("voice_follow_key", voice_follow_key);
REGISTER_KEYBOARD_ACTION(script_mouse_handler_name, script_trigger_lbutton);
+REGISTER_KEYBOARD_ACTION("game_control_button_0", game_control_button<0>);
+REGISTER_KEYBOARD_ACTION("game_control_button_1", game_control_button<1>);
+REGISTER_KEYBOARD_ACTION("game_control_button_2", game_control_button<2>);
+REGISTER_KEYBOARD_ACTION("game_control_button_3", game_control_button<3>);
+REGISTER_KEYBOARD_ACTION("game_control_button_4", game_control_button<4>);
+REGISTER_KEYBOARD_ACTION("game_control_button_5", game_control_button<5>);
+REGISTER_KEYBOARD_ACTION("game_control_button_6", game_control_button<6>);
+REGISTER_KEYBOARD_ACTION("game_control_button_7", game_control_button<7>);
+REGISTER_KEYBOARD_ACTION("game_control_button_8", game_control_button<8>);
+REGISTER_KEYBOARD_ACTION("game_control_button_9", game_control_button<9>);
+REGISTER_KEYBOARD_ACTION("game_control_button_10", game_control_button<10>);
+REGISTER_KEYBOARD_ACTION("game_control_button_11", game_control_button<11>);
+REGISTER_KEYBOARD_ACTION("game_control_button_12", game_control_button<12>);
+REGISTER_KEYBOARD_ACTION("game_control_button_13", game_control_button<13>);
+REGISTER_KEYBOARD_ACTION("game_control_button_14", game_control_button<14>);
+REGISTER_KEYBOARD_ACTION("game_control_button_15", game_control_button<15>);
+REGISTER_KEYBOARD_ACTION("game_control_button_16", game_control_button<16>);
+REGISTER_KEYBOARD_ACTION("game_control_button_17", game_control_button<17>);
+REGISTER_KEYBOARD_ACTION("game_control_button_18", game_control_button<18>);
+REGISTER_KEYBOARD_ACTION("game_control_button_19", game_control_button<19>);
+REGISTER_KEYBOARD_ACTION("game_control_button_20", game_control_button<20>);
+REGISTER_KEYBOARD_ACTION("game_control_button_21", game_control_button<21>);
+REGISTER_KEYBOARD_ACTION("game_control_button_22", game_control_button<22>);
+REGISTER_KEYBOARD_ACTION("game_control_button_23", game_control_button<23>);
+REGISTER_KEYBOARD_ACTION("game_control_button_24", game_control_button<24>);
+REGISTER_KEYBOARD_ACTION("game_control_button_25", game_control_button<25>);
+REGISTER_KEYBOARD_ACTION("game_control_button_26", game_control_button<26>);
+REGISTER_KEYBOARD_ACTION("game_control_button_27", game_control_button<27>);
+REGISTER_KEYBOARD_ACTION("game_control_button_28", game_control_button<28>);
+REGISTER_KEYBOARD_ACTION("game_control_button_29", game_control_button<29>);
+REGISTER_KEYBOARD_ACTION("game_control_button_30", game_control_button<30>);
+REGISTER_KEYBOARD_ACTION("game_control_button_31", game_control_button<31>);
#undef REGISTER_KEYBOARD_ACTION
LLViewerInput::LLViewerInput()
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index e2022cae37..01b97a6154 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -71,6 +71,9 @@
#include "llclipboard.h"
#include "llhttpretrypolicy.h"
#include "llsettingsvo.h"
+#include "llinventorylistener.h"
+
+LLInventoryListener sInventoryListener;
// do-nothing ops for use in callbacks.
void no_op_inventory_func(const LLUUID&) {}
@@ -966,7 +969,7 @@ void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id)
}
}
-void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp)
+void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace)
{
if (inv_item.isNull())
return;
@@ -974,7 +977,7 @@ void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachme
LLViewerInventoryItem *item = gInventory.getItem(inv_item);
if (item)
{
- rez_attachment(item, attachmentp);
+ rez_attachment(item, attachmentp, replace);
}
}
@@ -1436,7 +1439,8 @@ void update_inventory_category(
if(obj)
{
if (LLFolderType::lookupIsProtectedType(obj->getPreferredType())
- && (updates.size() != 1 || !updates.has("thumbnail")))
+ && (updates.size() != 1
+ || !(updates.has("thumbnail") || updates.has("favorite"))))
{
LLNotificationsUtil::add("CannotModifyProtectedCategories");
return;
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 21a6606253..18daa368d9 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -264,7 +264,7 @@ public:
class LLViewerJointAttachment;
-void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp);
+void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace);
void activate_gesture_cb(const LLUUID& inv_item);
diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp
index 7543fb3743..ffd595fd3b 100644
--- a/indra/newview/llviewerjoystick.cpp
+++ b/indra/newview/llviewerjoystick.cpp
@@ -41,6 +41,7 @@
#include "llagent.h"
#include "llagentcamera.h"
#include "llfocusmgr.h"
+#include "llgamecontrol.h"
#if LL_WINDOWS && !LL_MESA_HEADLESS
// Require DirectInput version 8
@@ -289,6 +290,7 @@ NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev)
ndof_dump(stderr, dev);
joystick->mNdofDev = dev;
joystick->mDriverState = JDS_INITIALIZED;
+ joystick->mDeviceIs3DConnexion = is3DConnexionDevice(joystick->mNdofDev->product);
res = NDOF_KEEP_HOTPLUGGED;
}
joystick->updateEnabled(true);
@@ -314,18 +316,11 @@ void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev)
// -----------------------------------------------------------------------------
LLViewerJoystick::LLViewerJoystick()
-: mDriverState(JDS_UNINITIALIZED),
- mNdofDev(NULL),
- mResetFlag(false),
- mCameraUpdated(true),
- mOverrideCamera(false),
- mJoystickRun(0)
{
for (int i = 0; i < 6; i++)
{
mAxes[i] = sDelta[i] = sLastDelta[i] = 0.0f;
}
-
memset(mBtn, 0, sizeof(mBtn));
// factor in bandwidth? bandwidth = gViewerStats->mKBitStat
@@ -404,6 +399,7 @@ void LLViewerJoystick::init(bool autoenable)
else
{
mDriverState = JDS_INITIALIZED;
+ mDeviceIs3DConnexion = is3DConnexionDevice(mNdofDev->product);
}
}
#endif
@@ -500,6 +496,7 @@ void LLViewerJoystick::initDevice(LLSD &guid)
else
{
mDriverState = JDS_INITIALIZED;
+ mDeviceIs3DConnexion = is3DConnexionDevice(mNdofDev->product);
}
}
#endif
@@ -584,6 +581,7 @@ bool LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE
else
{
mDriverState = JDS_INITIALIZED;
+ mDeviceIs3DConnexion = is3DConnexionDevice(mNdofDev->product);
return true;
}
#endif
@@ -599,6 +597,7 @@ void LLViewerJoystick::terminate()
ndof_libcleanup(); // frees alocated memory in mNdofDev
mDriverState = JDS_UNINITIALIZED;
mNdofDev = NULL;
+ mDeviceIs3DConnexion = false;
LL_INFOS("Joystick") << "Terminated connection with NDOF device." << LL_ENDL;
}
#endif
@@ -881,6 +880,10 @@ void LLViewerJoystick::moveObjects(bool reset)
{
gAgent.clearAFK();
}
+ else
+ {
+ gAwayTriggerTimer.reset();
+ }
if (sDelta[0] || sDelta[1] || sDelta[2])
{
@@ -1055,6 +1058,10 @@ void LLViewerJoystick::moveAvatar(bool reset)
{
gAgent.clearAFK();
}
+ else
+ {
+ gAwayTriggerTimer.reset();
+ }
setCameraNeedsUpdate(true);
}
@@ -1267,9 +1274,16 @@ void LLViewerJoystick::moveFlycam(bool reset)
}
// Clear AFK state if moved beyond the deadzone
- if (!is_zero && gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
+ if (!is_zero)
{
- gAgent.clearAFK();
+ if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
+ {
+ gAgent.clearAFK();
+ }
+ else
+ {
+ gAwayTriggerTimer.reset();
+ }
}
sFlycamPosition += LLVector3(sDelta) * sFlycamRotation;
@@ -1331,6 +1345,10 @@ bool LLViewerJoystick::toggleFlycam()
{
gAgent.clearAFK();
}
+ else
+ {
+ gAwayTriggerTimer.reset();
+ }
mOverrideCamera = !mOverrideCamera;
if (mOverrideCamera)
@@ -1350,7 +1368,9 @@ bool LLViewerJoystick::toggleFlycam()
void LLViewerJoystick::scanJoystick()
{
- if (mDriverState != JDS_INITIALIZED || !gSavedSettings.getBOOL("JoystickEnabled"))
+ if (mDriverState != JDS_INITIALIZED
+ || !gSavedSettings.getBOOL("JoystickEnabled")
+ || (!mDeviceIs3DConnexion && LLGameControl::isEnabled()))
{
return;
}
@@ -1513,14 +1533,23 @@ std::string LLViewerJoystick::getDescription()
return res;
}
+// static
+bool LLViewerJoystick::is3DConnexionDevice(const std::string& device_name)
+{
+ bool answer = device_name.find("Space") == 0
+ && ( (device_name.find("SpaceNavigator") == 0)
+ || (device_name.find("SpaceExplorer") == 0)
+ || (device_name.find("SpaceTraveler") == 0)
+ || (device_name.find("SpacePilot") == 0)
+ || (device_name.find("SpaceMouse") == 0));
+ return answer;
+}
+
bool LLViewerJoystick::isLikeSpaceNavigator() const
{
#if LIB_NDOF
return (isJoystickInitialized()
- && (strncmp(mNdofDev->product, "SpaceNavigator", 14) == 0
- || strncmp(mNdofDev->product, "SpaceExplorer", 13) == 0
- || strncmp(mNdofDev->product, "SpaceTraveler", 13) == 0
- || strncmp(mNdofDev->product, "SpacePilot", 10) == 0));
+ && is3DConnexionDevice(mNdofDev->product));
#else
return false;
#endif
diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h
index c989615653..aaf9abb437 100644
--- a/indra/newview/llviewerjoystick.h
+++ b/indra/newview/llviewerjoystick.h
@@ -81,6 +81,8 @@ public:
std::string getDescription();
void saveDeviceIdToSettings();
+ static bool is3DConnexionDevice(const std::string& device_name);
+
protected:
void updateEnabled(bool autoenable);
void handleRun(F32 inc);
@@ -100,19 +102,21 @@ protected:
private:
F32 mAxes[6];
long mBtn[16];
- EJoystickDriverState mDriverState;
- NDOF_Device *mNdofDev;
- bool mResetFlag;
- F32 mPerfScale;
- bool mCameraUpdated;
- bool mOverrideCamera;
- U32 mJoystickRun;
+ EJoystickDriverState mDriverState { JDS_UNINITIALIZED };
+ NDOF_Device *mNdofDev { nullptr };
// Windows: _GUID as U8 binary map
// MacOS: long as an U8 binary map
// Else: integer 1 for no device/ndof's default device
LLSD mLastDeviceUUID;
+ F32 mPerfScale;
+ U32 mJoystickRun { 0 };
+ bool mResetFlag { false };
+ bool mCameraUpdated { true };
+ bool mOverrideCamera { false };
+ bool mDeviceIs3DConnexion { false };
+
static F32 sLastDelta[7];
static F32 sDelta[7];
};
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 1dfa3a81bf..a9f5ba0d0b 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -2784,7 +2784,8 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
{
LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
- mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(false), native_key_data);
+ mMediaSource->textInput(ll_convert_to<std::string>(uni_char),
+ gKeyboard->currentMask(false), native_key_data);
}
}
@@ -2918,14 +2919,14 @@ void LLViewerMediaImpl::update()
media_tex->ref();
main_queue->postTo(
mTexUpdateQueue, // Worker thread queue
- [=]() // work done on update worker thread
+ [=, this]() // work done on update worker thread
{
#if LL_IMAGEGL_THREAD_CHECK
media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
#endif
doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true);
},
- [=]() // callback to main thread
+ [=, this]() // callback to main thread
{
#if LL_IMAGEGL_THREAD_CHECK
media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index cbc615b01a..c70b9b0c6e 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -56,6 +56,7 @@
// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0
#include "llattachmentsmgr.h"
// [/SL:KB]
+#include "llavataractions.h"
#include "llcompilequeue.h"
#include "llconsole.h"
#include "lldebugview.h"
@@ -75,6 +76,7 @@
#include "llfloaterpathfindingcharacters.h"
#include "llfloaterpathfindinglinksets.h"
#include "llfloaterpay.h"
+#include "llfloaterpreference.h"
#include "llfloaterreporter.h"
#include "llfloatersearch.h"
#include "fsfloatersearch.h"
@@ -83,18 +85,21 @@
#include "llfloatertools.h"
#include "llfloaterworldmap.h"
#include "llfloaterbuildoptions.h"
-#include "llavataractions.h"
-#include "lllandmarkactions.h"
+#include "fsyspath.h"
+#include "llgamecontrol.h"
#include "llgroupmgr.h"
+#include "lllandmarkactions.h"
#include "lltooltip.h"
#include "lltoolface.h"
#include "llhints.h"
#include "llhudeffecttrail.h"
+#include "llhudeffectresetskeleton.h"
#include "llhudmanager.h"
#include "llimview.h"
#include "llinventorybridge.h"
#include "llinventorydefines.h"
#include "llinventoryfunctions.h"
+#include "llluamanager.h"
#include "llpanellogin.h"
#include "llpanelblockedlist.h"
#include "llpanelmaininventory.h"
@@ -118,6 +123,7 @@
#include "lltoolmgr.h"
#include "lltoolpie.h"
#include "lltoolselectland.h"
+#include "llterrainpaintmap.h"
#include "lltrans.h"
#include "llviewerdisplay.h" //for gWindowResized
#include "llviewergenericmessage.h"
@@ -152,6 +158,7 @@
#include "llviewershadermgr.h"
#include "gltfscenemanager.h"
#include "gltf/asset.h"
+#include "rlvcommon.h"
using namespace LLAvatarAppearanceDefines;
@@ -175,6 +182,8 @@ extern bool gShaderProfileFrame;
// Globals
//
+LLUIListener sUIListener;
+
LLMenuBarGL *gMenuBarView = NULL;
LLViewerMenuHolderGL *gMenuHolder = NULL;
LLMenuGL *gPopupMenuView = NULL;
@@ -347,8 +356,6 @@ private:
static LLMenuParcelObserver* gMenuParcelObserver = NULL;
-static LLUIListener sUIListener;
-
LLMenuParcelObserver::LLMenuParcelObserver()
{
mLandBuyHandle = gMenuLand->getChild<LLMenuItemCallGL>("Land Buy")->getHandle();
@@ -946,17 +953,46 @@ class LLAdvancedToggleFeature : public view_listener_t
class LLAdvancedCheckFeature : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
-{
- U32 feature = feature_from_string( userdata.asString() );
- bool new_value = false;
+ {
+ U32 feature = feature_from_string( userdata.asString() );
+ bool new_value = false;
+
+ if ( feature != 0 )
+ {
+ new_value = LLPipeline::toggleRenderDebugFeatureControl( feature );
+ }
+
+ return new_value;
+ }
+};
- if ( feature != 0 )
+class LLAdvancedToggleExperiment : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
{
- new_value = LLPipeline::toggleRenderDebugFeatureControl( feature );
+ std::string feature = userdata.asString();
+ if (feature == "GameControl")
+ {
+ LLGameControl::setEnabled(! LLGameControl::isEnabled());
+ LLFloaterPreference::refreshInstance();
+ return true;
+ }
+ return false;
}
+};
- return new_value;
-}
+class LLAdvancedCheckExperiment : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool value = false;
+ std::string feature = userdata.asString();
+ if (feature == "GameControl")
+ {
+ value = LLGameControl::isEnabled();
+ }
+ return value;
+ }
};
class LLAdvancedCheckDisplayTextureDensity : public view_listener_t
@@ -1400,16 +1436,21 @@ class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t
return false;
}
+ // This calls gLocalTerrainMaterials.setPaintType
+ // It also ensures the terrain bake shader is compiled (handleSetShaderChanged), so call this first
+ // *TODO: Fix compile errors in shader so it can be used for all platforms. Then we can unhide the shader from behind this setting and remove the hook to handleSetShaderChanged. This advanced setting is intended to be used as a local setting for testing terrain, not a feature flag, but it is currently used like a feature flag as a temporary hack.
+ // *TODO: Ideally we would call setPaintType *after* the paint map is well-defined. The terrain draw pool should be able to handle an undefined paint map in the meantime.
+ gSavedSettings.setBOOL("LocalTerrainPaintEnabled", true);
+
U16 dim = (U16)gSavedSettings.getU32("TerrainPaintResolution");
// Ensure a reasonable image size of power two
const U32 max_resolution = gSavedSettings.getU32("RenderMaxTextureResolution");
dim = llclamp(dim, 16, max_resolution);
dim = 1 << U32(std::ceil(std::log2(dim)));
+ // TODO: Could probably get away with not using image raw here, now that we aren't writing bits via the CPU (see load_exr for example)
LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
LLPointer<LLViewerTexture> tex = LLViewerTextureManager::getLocalTexture(image_raw.get(), true);
const bool success = LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(*region, *tex);
- // This calls gLocalTerrainMaterials.setPaintType
- gSavedSettings.setBOOL("LocalTerrainPaintEnabled", true);
// If baking the paintmap failed, set the paintmap to nullptr. This
// causes LLDrawPoolTerrain to use a blank paintmap instead.
if (!success) { tex = nullptr; }
@@ -1419,6 +1460,92 @@ class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t
}
};
+class LLAdvancedTerrainEditLocalPaintMap : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerTexture* tex = gLocalTerrainMaterials.getPaintMap();
+ if (!tex)
+ {
+ LL_WARNS() << "No local paint map available to edit" << LL_ENDL;
+ return false;
+ }
+
+ LLTerrainBrushQueue& brush_queue = gLocalTerrainMaterials.getBrushQueue();
+ LLTerrainPaintQueue& paint_request_queue = gLocalTerrainMaterials.getPaintRequestQueue();
+
+ const LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ LL_WARNS() << "No current region for calculating paint operations" << LL_ENDL;
+ return false;
+ }
+ // TODO: Create the brush
+ // Just a dab for now
+ LLTerrainBrush::ptr_t brush = std::make_shared<LLTerrainBrush>();
+ brush->mBrushSize = 16.0f;
+ brush->mPath.emplace_back(17.0f, 17.0f);
+ brush->mPathOffset = 0;
+ brush->mPathEnd = true;
+ brush_queue.enqueue(brush);
+ LLTerrainPaintQueue brush_as_paint_queue = LLTerrainPaintMap::convertBrushQueueToPaintRGB(*region, *tex, brush_queue);
+ //paint_send_queue.enqueue(brush_as_paint_queue); // TODO: What was this line for? (it might also be a leftover line from an unfinished edit)
+
+ // TODO: Keep this around for later testing (i.e. when reducing framebuffer size and the offsets that requires)
+#if 0
+ // Enqueue a paint
+ // Modifies a subsection of the region paintmap with the material in
+ // the last slot.
+ // It is currently the responsibility of the paint queue to convert
+ // incoming bits to the right bit depth for the paintmap (this could
+ // change in the future).
+ LLTerrainPaint::ptr_t paint = std::make_shared<LLTerrainPaint>();
+ const U16 width = 33;
+ paint->mStartX = 1;
+ paint->mStartY = 1;
+ paint->mWidthX = width;
+ paint->mWidthY = width;
+ constexpr U8 bit_depth = 5;
+ paint->mBitDepth = bit_depth;
+ constexpr U8 max_value = (1 << bit_depth) - 1;
+ const size_t pixel_count = width * width;
+ const U8 components = LLTerrainPaint::RGBA;
+ paint->mComponents = components;
+ paint->mData.resize(components * pixel_count);
+ for (size_t h = 0; h < paint->mWidthY; ++h)
+ {
+ for (size_t w = 0; w < paint->mWidthX; ++w)
+ {
+ const size_t pixel = (h * paint->mWidthX) + w;
+ // Solid blue color
+ paint->mData[(components*pixel) + components - 2] = max_value; // blue
+ //// Alpha grid: 1.0 if odd for either dimension, 0.0 otherwise
+ //const U8 alpha = U8(F32(max_value) * F32(bool(w % 2) || bool(h % 2)));
+ //paint->mData[(components*pixel) + components - 1] = alpha; // alpha
+ // Alpha "frame"
+ const bool edge = w == 0 || h == 0 || w == (paint->mWidthX - 1) || h == (paint->mWidthY - 1);
+ const bool near_edge_frill = ((w == 1 || w == (paint->mWidthX - 2)) && (h % 2 == 0)) ||
+ ((h == 1 || h == (paint->mWidthY - 2)) && (w % 2 == 0));
+ const U8 alpha = U8(F32(max_value) * F32(edge || near_edge_frill));
+ paint->mData[(components*pixel) + components - 1] = alpha; // alpha
+ }
+ }
+ paint_request_queue.enqueue(paint);
+#endif
+
+ // Apply the paint queues ad-hoc right here for now.
+ // *TODO: Eventually the paint queue(s) should be applied at a
+ // predictable time in the viewer frame loop.
+ // TODO: In hindsight... maybe we *should* bind the paintmap to the render buffer. That makes a lot more sense, and we wouldn't have to reduce its resolution by settling for the bake buffer. If we do that, make a comment above convertPaintQueueRGBAToRGB that the texture is modified!
+ LLTerrainPaintQueue paint_send_queue = LLTerrainPaintMap::convertPaintQueueRGBAToRGB(*tex, paint_request_queue);
+ LLTerrainPaintQueue& paint_map_queue = gLocalTerrainMaterials.getPaintMapQueue();
+ paint_map_queue.enqueue(paint_send_queue);
+ LLTerrainPaintMap::applyPaintQueueRGB(*tex, paint_map_queue);
+
+ return true;
+ }
+};
+
class LLAdvancedTerrainDeleteLocalPaintMap : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -1849,7 +1976,6 @@ class LLAdvancedAppearanceToXML : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- std::string emptyname;
LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
LLVOAvatar *avatar = NULL;
if (obj)
@@ -1876,7 +2002,7 @@ class LLAdvancedAppearanceToXML : public view_listener_t
}
if (avatar)
{
- avatar->dumpArchetypeXML(emptyname);
+ avatar->dumpArchetypeXML(LLStringUtil::null);
}
return true;
}
@@ -5621,6 +5747,38 @@ class LLToolsEnablePathfindingRebakeRegion : public view_listener_t
}
};
+class LLToolsCheckSelectionLODMode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string param = userdata.asString();
+ static LLCachedControl<S32> debug_selection_lods(gSavedSettings, "DebugSelectionLODs", 0);
+ if ("default" == param)
+ {
+ return debug_selection_lods() < 0;
+ }
+ else if ("high" == param)
+ {
+ return debug_selection_lods() == 3;
+ }
+ else if ("medium" == param)
+ {
+ return debug_selection_lods() == 2;
+ }
+ else if ("low" == param)
+ {
+ return debug_selection_lods() == 1;
+ }
+ else if ("lowest" == param)
+ {
+ return debug_selection_lods() == 0;
+ }
+
+ return false;
+ }
+};
+
+
// Round the position of all root objects to the grid
class LLToolsSnapObjectXY : public view_listener_t
{
@@ -6259,6 +6417,8 @@ void show_debug_menus()
gMenuBarView->setItemVisible("Advanced", debug);
// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden
+ Rlv::Util::menuToggleVisible();
+
gMenuBarView->setItemVisible("Debug", qamode);
gMenuBarView->setItemEnabled("Debug", qamode);
@@ -6645,7 +6805,17 @@ class LLAvatarResetSkeleton : public view_listener_t
{
if (LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
{
- avatar->resetSkeleton(false);
+ if(avatar->getID() == gAgentID)
+ {
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject((LLViewerObject*)avatar);
+ effectp->setResetAnimations(false);
+ }
+ else
+ {
+ avatar->resetSkeleton(false);
+ }
}
return true;
}
@@ -6669,7 +6839,17 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t
{
if (LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
{
- avatar->resetSkeleton(true);
+ if(avatar->getID() == gAgentID)
+ {
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject((LLViewerObject*)avatar);
+ effectp->setResetAnimations(true);
+ }
+ else
+ {
+ avatar->resetSkeleton(true);
+ }
}
return true;
}
@@ -6697,11 +6877,24 @@ class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t
{
if (LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
{
- avatar->resetSkeleton(true);
+ if(avatar->getID() == gAgentID)
+ {
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject((LLViewerObject*)avatar);
+ effectp->setResetAnimations(true);
+ }
+ else
+ {
+ avatar->resetSkeleton(true);
+ }
}
else
{
- gAgentAvatarp->resetSkeleton(true);
+ LLHUDEffectResetSkeleton* effectp = (LLHUDEffectResetSkeleton*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_RESET_SKELETON, true);
+ effectp->setSourceObject(gAgentAvatarp);
+ effectp->setTargetObject(gAgentAvatarp);
+ effectp->setResetAnimations(true);
}
return true;
}
@@ -7794,15 +7987,29 @@ class LLAvatarSendIM : public view_listener_t
class LLAvatarCall : public view_listener_t
{
+ static LLVOAvatar* findAvatar()
+ {
+ return find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ }
+
bool handleEvent(const LLSD& userdata)
{
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
+ if (LLVOAvatar* avatar = findAvatar())
{
LLAvatarActions::startCall(avatar->getID());
}
return true;
}
+
+public:
+ static bool isAvailable()
+ {
+ if (LLVOAvatar* avatar = findAvatar())
+ {
+ return LLAvatarActions::canCallTo(avatar->getID());
+ }
+ return LLAvatarActions::canCall();
+ }
};
namespace
@@ -8547,6 +8754,36 @@ class LLToolsSelectBySurrounding : public view_listener_t
}
};
+class LLToolsSelectionLODMode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string param = userdata.asString();
+ if ("default" == param)
+ {
+ gSavedSettings.setS32("DebugSelectionLODs", -1);
+ }
+ else if ("high" == param)
+ {
+ gSavedSettings.setS32("DebugSelectionLODs", 3);
+ }
+ else if ("medium" == param)
+ {
+ gSavedSettings.setS32("DebugSelectionLODs", 2);
+ }
+ else if ("low" == param)
+ {
+ gSavedSettings.setS32("DebugSelectionLODs", 1);
+ }
+ else if ("lowest" == param)
+ {
+ gSavedSettings.setS32("DebugSelectionLODs", 0);
+ }
+
+ return true;
+ }
+};
+
class LLToolsShowHiddenSelection : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -9278,80 +9515,89 @@ class LLToolsSelectTool : public view_listener_t
};
/// WINDLIGHT callbacks
-class LLWorldEnvSettings : public view_listener_t
+void defocusEnvFloaters()
{
- void defocusEnvFloaters()
+ // currently there is only one instance of each floater
+ std::vector<std::string> env_floaters_names = {"env_edit_extdaycycle", "env_fixed_environmentent_water",
+ "env_fixed_environmentent_sky"};
+ for (std::vector<std::string>::const_iterator it = env_floaters_names.begin(); it != env_floaters_names.end(); ++it)
{
- //currently there is only one instance of each floater
- std::vector<std::string> env_floaters_names = { "env_edit_extdaycycle", "env_fixed_environmentent_water", "env_fixed_environmentent_sky" };
- for (std::vector<std::string>::const_iterator it = env_floaters_names.begin(); it != env_floaters_names.end(); ++it)
+ LLFloater *env_floater = LLFloaterReg::findTypedInstance<LLFloater>(*it);
+ if (env_floater)
{
- LLFloater* env_floater = LLFloaterReg::findTypedInstance<LLFloater>(*it);
- if (env_floater)
- {
- env_floater->setFocus(false);
- }
+ env_floater->setFocus(false);
}
}
+}
- bool handleEvent(const LLSD& userdata)
+bool handle_env_setting_event(std::string event_name)
+{
+ if (event_name == "sunrise")
{
- std::string event_name = userdata.asString();
-
- if (event_name == "sunrise")
- {
- LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNRISE, LLEnvironment::TRANSITION_INSTANT);
- LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
- defocusEnvFloaters();
- }
- else if (event_name == "noon")
- {
- LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDDAY, LLEnvironment::TRANSITION_INSTANT);
- LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
- defocusEnvFloaters();
- }
- else if (event_name == "legacy noon")
- {
- LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY, LLEnvironment::TRANSITION_INSTANT);
- LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
- defocusEnvFloaters();
- }
- else if (event_name == "sunset")
- {
- LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNSET, LLEnvironment::TRANSITION_INSTANT);
- LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
- defocusEnvFloaters();
- }
- else if (event_name == "midnight")
- {
- LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDNIGHT, LLEnvironment::TRANSITION_INSTANT);
- LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
- defocusEnvFloaters();
- }
- else if (event_name == "region")
- {
- // reset probe data when reverting back to region sky setting
- gPipeline.mReflectionMapManager.reset();
+ LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNRISE,
+ LLEnvironment::TRANSITION_INSTANT);
+ LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
+ defocusEnvFloaters();
+ }
+ else if (event_name == "noon")
+ {
+ LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDDAY,
+ LLEnvironment::TRANSITION_INSTANT);
+ LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
+ defocusEnvFloaters();
+ }
+ else if (event_name == "legacy noon")
+ {
+ LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY, LLEnvironment::TRANSITION_INSTANT);
+ LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
+ defocusEnvFloaters();
+ }
+ else if (event_name == "sunset")
+ {
+ LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_SUNSET,
+ LLEnvironment::TRANSITION_INSTANT);
+ LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
+ defocusEnvFloaters();
+ }
+ else if (event_name == "midnight")
+ {
+ LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::KNOWN_SKY_MIDNIGHT,
+ LLEnvironment::TRANSITION_INSTANT);
+ LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
+ defocusEnvFloaters();
+ }
+ else if (event_name == "region")
+ {
+ // reset probe data when reverting back to region sky setting
+ gPipeline.mReflectionMapManager.reset();
- LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL);
- LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
- defocusEnvFloaters();
- }
- else if (event_name == "pause_clouds")
- {
- if (LLEnvironment::instance().isCloudScrollPaused())
- LLEnvironment::instance().resumeCloudScroll();
+ LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL);
+ LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
+ defocusEnvFloaters();
+ }
+ else if (event_name == "pause_clouds")
+ {
+ if (LLEnvironment::instance().isCloudScrollPaused())
+ LLEnvironment::instance().resumeCloudScroll();
else
- LLEnvironment::instance().pauseCloudScroll();
- }
- else if (event_name == "adjust_tool")
- {
- LLFloaterReg::showInstance("env_adjust_snapshot");
- }
- else if (event_name == "my_environs")
- {
- LLFloaterReg::showInstance("my_environments");
- }
+ LLEnvironment::instance().pauseCloudScroll();
+ }
+ else if (event_name == "adjust_tool")
+ {
+ LLFloaterReg::showInstance("env_adjust_snapshot");
+ }
+ else if (event_name == "my_environs")
+ {
+ LLFloaterReg::showInstance("my_environments");
+ }
+ return true;
+}
+
+class LLWorldEnvSettings : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_env_setting_event(userdata.asString());
return true;
}
@@ -9459,17 +9705,6 @@ class LLWorldEnableEnvPreset : public view_listener_t
}
};
-
-/// Post-Process callbacks
-class LLWorldPostProcess : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterReg::showInstance("env_post_process");
- return true;
- }
-};
-
class LLWorldCheckBanLines : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@@ -9577,6 +9812,18 @@ void LLUploadCostCalculator::calculateCost(const std::string& asset_type_str)
mCostStr = std::to_string(upload_cost);
}
+void lua_run_script(const LLSD& userdata)
+{
+ std::string script_path = userdata.asString();
+ if (script_path.empty())
+ {
+ LL_WARNS() << "Script name is not specified" << LL_ENDL;
+ return;
+ }
+
+ LLLUAmanager::runScriptFile(script_path);
+}
+
void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y)
{
static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml",
@@ -9637,16 +9884,18 @@ void initialize_edit_menu()
}
+typedef LLUICtrl::CommitCallbackInfo cb_info;
+
void initialize_spellcheck_menu()
{
- LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar();
+ LLUICtrl::CommitRegistrarHelper registrar(LLUICtrl::CommitCallbackRegistry::defaultRegistrar());
LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar();
- commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2));
+ registrar.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2), cb_info::UNTRUSTED_BLOCK);
enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2));
- commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1));
+ registrar.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1), cb_info::UNTRUSTED_BLOCK);
enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1));
- commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1));
+ registrar.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1), cb_info::UNTRUSTED_BLOCK);
enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1));
}
@@ -9670,8 +9919,8 @@ void initialize_menus()
bool mMult;
};
+ LLUICtrl::CommitRegistrarHelper registrar(LLUICtrl::CommitCallbackRegistry::currentRegistrar());
LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar();
- LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar();
// Generic enable and visible
// Don't prepend MenuName.Foo because these can be used in any menu.
@@ -9686,11 +9935,11 @@ void initialize_menus()
enable.add("Conversation.IsConversationLoggingAllowed", boost::bind(&LLFloaterIMContainer::isConversationLoggingAllowed));
// Agent
- commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
+ registrar.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
enable.add("Agent.enableFlyLand", boost::bind(&enable_fly_land));
- commit.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2));
- commit.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2));
- commit.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2));
+ registrar.add("Agent.PressMicrophone", boost::bind(&LLAgent::pressMicrophone, _2), cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Agent.ReleaseMicrophone", boost::bind(&LLAgent::releaseMicrophone, _2), cb_info::UNTRUSTED_BLOCK);
+ registrar.add("Agent.ToggleMicrophone", boost::bind(&LLAgent::toggleMicrophone, _2), cb_info::UNTRUSTED_BLOCK);
enable.add("Agent.IsMicrophoneOn", boost::bind(&LLAgent::isMicrophoneOn, _2));
enable.add("Agent.IsActionAllowed", boost::bind(&LLAgent::isActionAllowed, _2));
@@ -9702,12 +9951,12 @@ void initialize_menus()
view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape");
view_listener_t::addMenu(new LLEnableHoverHeight(), "Edit.EnableHoverHeight");
view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics");
- commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar));
- commit.add("NowWearing", boost::bind(&handle_now_wearing));
- commit.add("EditOutfit", boost::bind(&handle_edit_outfit));
- commit.add("EditShape", boost::bind(&handle_edit_shape));
- commit.add("HoverHeight", boost::bind(&handle_hover_height));
- commit.add("EditPhysics", boost::bind(&handle_edit_physics));
+ registrar.add("CustomizeAvatar", boost::bind(&handle_customize_avatar));
+ registrar.add("NowWearing", boost::bind(&handle_now_wearing));
+ registrar.add("EditOutfit", boost::bind(&handle_edit_outfit));
+ registrar.add("EditShape", boost::bind(&handle_edit_shape));
+ registrar.add("HoverHeight", boost::bind(&handle_hover_height));
+ registrar.add("EditPhysics", boost::bind(&handle_edit_physics));
// View menu
view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook");
@@ -9760,7 +10009,6 @@ void initialize_menus()
view_listener_t::addMenu(new LLWorldEnableEnvSettings(), "World.EnableEnvSettings");
view_listener_t::addMenu(new LLWorldEnvPreset(), "World.EnvPreset");
view_listener_t::addMenu(new LLWorldEnableEnvPreset(), "World.EnableEnvPreset");
- view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess");
view_listener_t::addMenu(new LLWorldCheckBanLines() , "World.CheckBanLines");
view_listener_t::addMenu(new LLWorldShowBanLines() , "World.ShowBanLines");
@@ -9771,20 +10019,21 @@ void initialize_menus()
view_listener_t::addMenu(new LLToolsSelectInvisibleObjects(), "Tools.SelectInvisibleObjects");
view_listener_t::addMenu(new LLToolsSelectReflectionProbes(), "Tools.SelectReflectionProbes");
view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding");
+ view_listener_t::addMenu(new LLToolsSelectionLODMode(), "Tools.SelectionLODMode");
view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection");
view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius");
view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts");
view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY");
view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid");
view_listener_t::addMenu(new LLToolsSelectNextPartFace(), "Tools.SelectNextPart");
- commit.add("Tools.Link", boost::bind(&handle_link_objects));
- commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
+ registrar.add("Tools.Link", boost::bind(&handle_link_objects));
+ registrar.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations");
view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys");
- commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2));
- commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take));
- commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy));
+ registrar.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2));
+ registrar.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take), cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("Tools.TakeCopy", boost::bind(&handle_take_copy), cb_info::UNTRUSTED_THROTTLE);
view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory");
view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction");
@@ -9803,6 +10052,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLToolsEnablePathfindingView(), "Tools.EnablePathfindingView");
view_listener_t::addMenu(new LLToolsDoPathfindingRebakeRegion(), "Tools.DoPathfindingRebakeRegion");
view_listener_t::addMenu(new LLToolsEnablePathfindingRebakeRegion(), "Tools.EnablePathfindingRebakeRegion");
+ view_listener_t::addMenu(new LLToolsCheckSelectionLODMode(), "Tools.ToolsCheckSelectionLODMode");
// Help menu
// most items use the ShowFloater method
@@ -9828,6 +10078,9 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature");
view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature");
+ view_listener_t::addMenu(new LLAdvancedToggleExperiment(), "Advanced.ToggleExperiment");
+ view_listener_t::addMenu(new LLAdvancedCheckExperiment(), "Advanced.CheckExperiment");
+
view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity");
view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity");
@@ -9835,7 +10088,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay");
view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay");
view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo");
- commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info));
+ registrar.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info));
view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
// Develop > Render
@@ -9848,13 +10101,14 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption");
view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
- view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview");
- view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
- view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
- view_listener_t::addMenu(new LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload");
- view_listener_t::addMenu(new LLAdvancedClickGLTFEdit(), "Advanced.ClickGLTFEdit");
- view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow");
- view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
+ view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedClickGLTFEdit(), "Advanced.ClickGLTFEdit", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain", cb_info::UNTRUSTED_BLOCK);
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
@@ -9874,18 +10128,19 @@ void initialize_menus()
// Develop > Terrain
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
view_listener_t::addMenu(new LLAdvancedTerrainCreateLocalPaintMap(), "Advanced.TerrainCreateLocalPaintMap");
+ view_listener_t::addMenu(new LLAdvancedTerrainEditLocalPaintMap(), "Advanced.TerrainEditLocalPaintMap");
view_listener_t::addMenu(new LLAdvancedTerrainDeleteLocalPaintMap(), "Advanced.TerrainDeleteLocalPaintMap");
// Advanced > UI
- commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
- commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
- commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2));
- commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2));
+ registrar.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
+ registrar.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
+ registrar.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2));
+ registrar.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2));
view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
- commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) );
- commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) );
+ registrar.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers), cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus));
view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo");
view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo");
view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks");
@@ -9906,11 +10161,11 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc");
// Advanced > XUI
- commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance()));
+ registrar.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance()));
view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames");
view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames");
view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs");
- commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches));
+ registrar.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches), cb_info::UNTRUSTED_BLOCK);
// Advanced > Character > Grab Baked Texture
view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture");
@@ -9921,8 +10176,8 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML");
view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry");
- view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale");
- view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale");
+ view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale", cb_info::UNTRUSTED_THROTTLE);
+ view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale", cb_info::UNTRUSTED_THROTTLE);
// Advanced > Character > Animation Speed
view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster");
@@ -9947,7 +10202,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments");
view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures");
// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0
- commit.add("Advanced.RefreshAttachments", boost::bind(&handle_refresh_attachments));
+ registrar.add("Advanced.RefreshAttachments", boost::bind(&handle_refresh_attachments));
// [/SL:KB]
view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures");
view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures");
@@ -9957,7 +10212,7 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket");
// Advanced > Cache
- view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache");
+ view_listener_t::addMenu(new LLAdvancedPurgeDiskCache(), "Advanced.PurgeDiskCache", cb_info::UNTRUSTED_BLOCK);
// Advanced > Recorder
view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
@@ -9966,25 +10221,25 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedViewerEventRecorder(), "Advanced.EventRecorder");
// Advanced > Debugging
- view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
- view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror");
- view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg");
- view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess");
- view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro");
- view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop");
- view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException");
- view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException");
- view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro");
- view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash");
- view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash");
- view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash");
- view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer");
+ view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorLlerrorMsg(), "Advanced.ForceErrorLlerrorMsg", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccessCoro(), "Advanced.ForceErrorBadMemoryAccessCoro", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceOSException(), "Advanced.ForceErrorOSException", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash", cb_info::UNTRUSTED_BLOCK);
+ view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer", cb_info::UNTRUSTED_BLOCK);
// Advanced (toplevel)
view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");
view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
- view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest");
+ view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest", cb_info::UNTRUSTED_BLOCK);
view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions");
@@ -9999,11 +10254,11 @@ void initialize_menus()
view_listener_t::addMenu(new LLDevelopSetLoggingLevel(), "Develop.SetLoggingLevel");
//Develop (clear cache immediately)
- commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) );
+ registrar.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately), cb_info::UNTRUSTED_BLOCK);
// Develop (Fonts debugging)
- commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts));
- commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures));
+ registrar.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts), cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures), cb_info::UNTRUSTED_THROTTLE);
// Admin >Object
view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");
@@ -10040,21 +10295,21 @@ void initialize_menus()
view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute");
view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend");
view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact");
- commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD()));
+ registrar.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD()));
view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug");
view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug");
view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup");
- commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
- commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector));
+ registrar.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
+ registrar.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector));
view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
- view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
- enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
- view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
+ view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call", cb_info::UNTRUSTED_BLOCK);
+ enable.add("Avatar.EnableCall", boost::bind(&LLAvatarCall::isAvailable));
+ view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse", cb_info::UNTRUSTED_THROTTLE);
view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile");
view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks");
view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch");
view_listener_t::addMenu(new FSToolsResyncAnimations(), "Tools.ResyncAnimations"); // <FS:CR> Resync Animations
- view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton");
+ view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton", cb_info::UNTRUSTED_THROTTLE);
view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton");
view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations");
view_listener_t::addMenu(new LLAvatarResetSelfSkeleton(), "Avatar.ResetSelfSkeleton");
@@ -10062,22 +10317,22 @@ void initialize_menus()
enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible));
enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible));
- commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL")));
+ registrar.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL")));
view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2));
// Object pie menu
view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
- commit.add("Object.Touch", boost::bind(&handle_object_touch));
- commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original));
- commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
- commit.add("Object.Delete", boost::bind(&handle_object_delete));
+ registrar.add("Object.Touch", boost::bind(&handle_object_touch));
+ registrar.add("Object.ShowOriginal", boost::bind(&handle_object_show_original));
+ registrar.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
+ registrar.add("Object.Delete", boost::bind(&handle_object_delete));
view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar");
view_listener_t::addMenu(new LLObjectReturn(), "Object.Return");
- commit.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance()));
- view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
+ registrar.add("Object.Duplicate", boost::bind(&LLSelectMgr::duplicate, LLSelectMgr::getInstance()));
+ view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse", cb_info::UNTRUSTED_THROTTLE);
view_listener_t::addMenu(new LLObjectMute(), "Object.Mute");
enable.add("Object.VisibleTake", boost::bind(&visible_take_object));
@@ -10086,15 +10341,15 @@ void initialize_menus()
enable.add("Object.EnableTakeMultiple", boost::bind(&enable_take_objects));
enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object));
- commit.add("Object.Buy", boost::bind(&handle_buy));
- commit.add("Object.Edit", boost::bind(&handle_object_edit));
- commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material));
- commit.add("Object.Inspect", boost::bind(&handle_object_inspect));
- commit.add("Object.Open", boost::bind(&handle_object_open));
- commit.add("Object.Take", boost::bind(&handle_take, false));
- commit.add("Object.TakeSeparate", boost::bind(&handle_take, true));
- commit.add("Object.TakeSeparateCopy", boost::bind(&handle_take_separate_copy));
- commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector));
+ registrar.add("Object.Buy", boost::bind(&handle_buy), cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("Object.Edit", boost::bind(&handle_object_edit));
+ registrar.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material));
+ registrar.add("Object.Inspect", boost::bind(&handle_object_inspect));
+ registrar.add("Object.Open", boost::bind(&handle_object_open));
+ registrar.add("Object.Take", boost::bind(&handle_take, false));
+ registrar.add("Object.TakeSeparate", boost::bind(&handle_take, true));
+ registrar.add("Object.TakeSeparateCopy", boost::bind(&handle_take_separate_copy));
+ registrar.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector));
enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect));
enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material));
enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
@@ -10113,7 +10368,7 @@ void initialize_menus()
enable.add("Object.EnableMute", boost::bind(&enable_object_mute));
enable.add("Object.EnableUnmute", boost::bind(&enable_object_unmute));
enable.add("Object.EnableBuy", boost::bind(&enable_buy_object));
- commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom"));
+ registrar.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom"));
// Attachment pie menu
enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2));
@@ -10135,14 +10390,14 @@ void initialize_menus()
view_listener_t::addMenu(new LLMuteParticle(), "Particle.Mute");
view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass");
- commit.add("Land.Buy", boost::bind(&handle_buy_land));
+ registrar.add("Land.Buy", boost::bind(&handle_buy_land), cb_info::UNTRUSTED_THROTTLE);
// Generic actions
- commit.add("ReportAbuse", boost::bind(&handle_report_abuse));
- commit.add("BuyCurrency", boost::bind(&handle_buy_currency));
+ registrar.add("ReportAbuse", boost::bind(&handle_report_abuse), cb_info::UNTRUSTED_THROTTLE);
+ registrar.add("BuyCurrency", boost::bind(&handle_buy_currency), cb_info::UNTRUSTED_THROTTLE);
view_listener_t::addMenu(new LLShowHelp(), "ShowHelp");
view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp");
- view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak");
+ view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak", cb_info::UNTRUSTED_BLOCK);
view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL");
view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile");
view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks");
@@ -10151,21 +10406,21 @@ void initialize_menus()
view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl");
view_listener_t::addMenu(new LLCheckControl(), "CheckControl");
view_listener_t::addMenu(new LLGoToObject(), "GoToObject");
- commit.add("PayObject", boost::bind(&handle_give_money_dialog));
+ registrar.add("PayObject", boost::bind(&handle_give_money_dialog));
- commit.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow));
+ registrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow), cb_info::UNTRUSTED_THROTTLE);
- commit.add("Inventory.OpenFavoriteFolder", boost::bind(&toggle_favorite_inventory_folder));
+ registrar.add("Inventory.OpenFavoriteFolder", boost::bind(&toggle_favorite_inventory_folder));
enable.add("Inventory.IsFavoriteFolderOpen", boost::bind(&favorite_inventory_folder_visible));
enable.add("EnablePayObject", boost::bind(&enable_pay_object));
enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar));
enable.add("EnableEdit", boost::bind(&enable_object_edit));
enable.add("EnableMuteParticle", boost::bind(&enable_mute_particle));
- commit.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects));
+ registrar.add("Pathfinding.Linksets.Select", boost::bind(&LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects));
enable.add("EnableSelectInPathfindingLinksets", boost::bind(&enable_object_select_in_pathfinding_linksets));
enable.add("VisibleSelectInPathfindingLinksets", boost::bind(&visible_object_select_in_pathfinding_linksets));
- commit.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects));
+ registrar.add("Pathfinding.Characters.Select", boost::bind(&LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects));
enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters));
enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception));
enable.add("EnableGLTF", boost::bind(&enable_gltf));
@@ -10181,4 +10436,6 @@ void initialize_menus()
view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected");
view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
+
+ registrar.add("Lua.RunScript", boost::bind(&lua_run_script, _2), cb_info::UNTRUSTED_BLOCK);
}
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 68ba740f67..49539b9e97 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -110,6 +110,7 @@ void handle_give_money_dialog();
bool enable_pay_object();
bool enable_buy_object();
bool handle_go_to();
+bool handle_env_setting_event(std::string event_name);
// Convert strings to internal types
U32 render_type_from_string(std::string_view render_type);
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index ce66dbc03f..02667a3ff6 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -478,13 +478,19 @@ const bool check_file_extension(const std::string& filename, LLFilePicker::ELoad
return true;
}
-const void upload_single_file(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type)
+void upload_single_file(
+ const std::vector<std::string>& filenames,
+ LLFilePicker::ELoadFilter type,
+ const LLUUID& dest)
{
std::string filename = filenames[0];
if (!check_file_extension(filename, type)) return;
if (!filename.empty())
{
+ LLSD args;
+ args["filename"] = filename;
+ args["dest"] = dest;
if (type == LLFilePicker::FFLOAD_WAV)
{
// pre-qualify wavs to make sure the format is acceptable
@@ -499,12 +505,12 @@ const void upload_single_file(const std::vector<std::string>& filenames, LLFileP
}
else
{
- LLFloaterReg::showInstance("upload_sound", LLSD(filename));
+ LLFloaterReg::showInstance("upload_sound", args);
}
}
if (type == LLFilePicker::FFLOAD_IMAGE)
{
- LLFloaterReg::showInstance("upload_image", LLSD(filename));
+ LLFloaterReg::showInstance("upload_image", args);
}
if (type == LLFilePicker::FFLOAD_ANIM)
{
@@ -512,18 +518,18 @@ const void upload_single_file(const std::vector<std::string>& filenames, LLFileP
LLStringUtil::toLower(filename_lc);
if (filename_lc.rfind(".anim") != std::string::npos)
{
- LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename));
+ LLFloaterReg::showInstance("upload_anim_anim", args);
}
else
{
- LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename));
+ LLFloaterReg::showInstance("upload_anim_bvh", args);
}
}
}
return;
}
-void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)
+void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k, const LLUUID& dest)
{
for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
{
@@ -570,7 +576,8 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)
LLFloaterPerms::getNextOwnerPerms("Uploads"),
LLFloaterPerms::getGroupPerms("Uploads"),
LLFloaterPerms::getEveryonePerms("Uploads"),
- expected_upload_cost);
+ expected_upload_cost,
+ dest);
if (!allow_2k)
{
@@ -595,14 +602,14 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)
// Todo:
// 1. Decouple bulk upload from material editor
// 2. Take into account possiblity of identical textures
- LLMaterialEditor::uploadMaterialFromModel(filename, model, i);
+ LLMaterialEditor::uploadMaterialFromModel(filename, model, i, dest);
}
}
}
}
}
-void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k, const LLSD& notification, const LLSD& response)
+void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k, const LLSD& notification, const LLSD& response, const LLUUID& dest)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option != 0)
@@ -611,7 +618,7 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k, const LLS
return;
}
- do_bulk_upload(filenames, allow_2k);
+ do_bulk_upload(filenames, allow_2k, dest);
}
bool get_bulk_upload_expected_cost(
@@ -709,7 +716,7 @@ bool get_bulk_upload_expected_cost(
return file_count > 0;
}
-const void upload_bulk(const std::vector<std::string>& filtered_filenames, bool allow_2k)
+const void upload_bulk(const std::vector<std::string>& filtered_filenames, bool allow_2k, const LLUUID& dest)
{
S32 expected_upload_cost;
S32 expected_upload_count;
@@ -721,6 +728,7 @@ const void upload_bulk(const std::vector<std::string>& filtered_filenames, bool
key["upload_cost"] = expected_upload_cost;
key["upload_count"] = expected_upload_count;
key["has_2k_textures"] = (textures_2k_count > 0);
+ key["dest"] = dest;
LLSD array;
for (const std::string& str : filtered_filenames)
@@ -754,7 +762,7 @@ const void upload_bulk(const std::vector<std::string>& filtered_filenames, bool
}
-const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type, bool allow_2k)
+void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type, bool allow_2k, const LLUUID& dest)
{
// TODO:
// Check user balance for entire cost
@@ -776,7 +784,7 @@ const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::
filtered_filenames.push_back(filename);
}
}
- upload_bulk(filtered_filenames, allow_2k);
+ upload_bulk(filtered_filenames, allow_2k, dest);
}
class LLFileUploadImage : public view_listener_t
@@ -787,7 +795,7 @@ class LLFileUploadImage : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false);
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, LLUUID::null), LLFilePicker::FFLOAD_IMAGE, false);
return true;
}
};
@@ -818,7 +826,7 @@ class LLFileUploadSound : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false);
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, LLUUID::null), LLFilePicker::FFLOAD_WAV, false);
return true;
}
};
@@ -831,7 +839,7 @@ class LLFileUploadAnim : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false);
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, LLUUID::null), LLFilePicker::FFLOAD_ANIM, false);
return true;
}
};
@@ -844,7 +852,9 @@ class LLFileUploadBulk : public view_listener_t
{
gAgentCamera.changeCameraToDefault();
}
- LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2, true), LLFilePicker::FFLOAD_ALL, true);
+
+ LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2, true, LLUUID::null), LLFilePicker::FFLOAD_ALL, true);
+
return true;
}
};
@@ -906,16 +916,22 @@ class LLFileEnableCloseAllWindows : public view_listener_t
}
};
+void close_all_windows()
+{
+ bool app_quitting = false;
+ gFloaterView->closeAllChildren(app_quitting);
+ LLFloaterSnapshot *floater_snapshot = LLFloaterSnapshot::findInstance();
+ if (floater_snapshot)
+ floater_snapshot->closeFloater(app_quitting);
+ if (gMenuHolder)
+ gMenuHolder->hideMenus();
+}
+
class LLFileCloseAllWindows : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- bool app_quitting = false;
- gFloaterView->closeAllChildren(app_quitting);
- LLFloaterSnapshot* floater_snapshot = LLFloaterSnapshot::findInstance();
- if (floater_snapshot)
- floater_snapshot->closeFloater(app_quitting);
- if (gMenuHolder) gMenuHolder->hideMenus();
+ close_all_windows();
return true;
}
};
@@ -1132,7 +1148,7 @@ LLUUID upload_new_resource(
name, desc, compression_info,
destination_folder_type, inv_type,
next_owner_perms, group_perms, everyone_perms,
- expected_upload_cost, show_inventory));
+ expected_upload_cost, LLUUID::null, show_inventory));
upload_new_resource(uploadInfo, callback, userdata);
return LLUUID::null;
diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h
index d99f9dc4c6..0b0de38c94 100644
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -72,7 +72,20 @@ bool get_bulk_upload_expected_cost(
S32& bvh_count,
S32& textures_2k_count);
-void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k);
+void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k, const LLUUID& dest);
+
+void close_all_windows();
+
+void upload_single_file(
+ const std::vector<std::string>& filenames,
+ LLFilePicker::ELoadFilter type,
+ const LLUUID& dest);
+
+void upload_bulk(
+ const std::vector<std::string>& filenames,
+ LLFilePicker::ELoadFilter type,
+ bool allow_2k,
+ const LLUUID& dest);
//consider moving all file pickers below to more suitable place
class LLFilePickerThread : public LLThread
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 1d4828fd33..d722851851 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -118,6 +118,8 @@
#include "llpanelplaceprofile.h"
#include "llviewerregion.h"
#include "llfloaterregionrestarting.h"
+#include "rlvactions.h"
+#include "rlvhandler.h"
#include "llnotificationmanager.h" //
#include "llexperiencecache.h"
@@ -2137,6 +2139,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
EInstantMessage dialog = (EInstantMessage)d;
LLHost sender = msg->getSender();
+ LLSD metadata;
+ if (msg->getNumberOfBlocksFast(_PREHASH_MetaData) > 0)
+ {
+ S32 metadata_size = msg->getSizeFast(_PREHASH_MetaData, 0, _PREHASH_Data);
+ std::string metadata_buffer;
+ metadata_buffer.resize(metadata_size, 0);
+
+ msg->getBinaryDataFast(_PREHASH_MetaData, _PREHASH_Data, &metadata_buffer[0], metadata_size, 0, metadata_size );
+ std::stringstream metadata_stream(metadata_buffer);
+ if (LLSDSerialize::fromBinary(metadata, metadata_stream, metadata_size) == LLSDParser::PARSE_FAILURE)
+ {
+ metadata.clear();
+ }
+ }
+
LLIMProcessing::processNewMessage(from_id,
from_group,
to_id,
@@ -2151,7 +2168,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
position,
binary_bucket,
binary_bucket_size,
- sender);
+ sender,
+ metadata);
}
void send_do_not_disturb_message (LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id)
@@ -2382,15 +2400,16 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
}
bool is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible);
+ bool show_script_chat_particles = chat.mSourceType == CHAT_SOURCE_OBJECT
+ && chat.mChatType != CHAT_TYPE_DEBUG_MSG
+ && gSavedSettings.getBOOL("EffectScriptChatParticles");
chatter = gObjectList.findObject(from_id);
if (chatter)
{
chat.mPosAgent = chatter->getPositionAgent();
// Make swirly things only for talking objects. (not script debug messages, though)
- if (chat.mSourceType == CHAT_SOURCE_OBJECT
- && chat.mChatType != CHAT_TYPE_DEBUG_MSG
- && gSavedSettings.getBOOL("EffectScriptChatParticles") )
+ if (show_script_chat_particles && (!RlvActions::isRlvEnabled() || CHAT_TYPE_OWNER != chat.mChatType) )
{
LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
psc->setSourceObject(chatter);
@@ -2422,8 +2441,11 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
bool ircstyle = false;
+ auto [message, is_script] = LLStringUtil::withoutPrefix(mesg, LUA_PREFIX);
+ chat.mIsScript = is_script;
+
// Look for IRC-style emotes here so chatbubbles work
- std::string prefix = mesg.substr(0, 4);
+ std::string prefix = message.substr(0, 4);
if (prefix == "/me " || prefix == "/me'")
{
ircstyle = true;
@@ -2465,19 +2487,42 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
else
{
chat.mText = "";
+ auto [msg_without_prefix, is_lua] = LLStringUtil::withoutPrefix(mesg, LUA_PREFIX);
+ std::string prefix;
+ if (is_lua)
+ {
+ prefix = LUA_PREFIX;
+ }
switch(chat.mChatType)
{
case CHAT_TYPE_WHISPER:
- chat.mText = LLTrans::getString("whisper") + " ";
+ prefix += LLTrans::getString("whisper") + " ";
+ break;
+ case CHAT_TYPE_SHOUT:
+ prefix += LLTrans::getString("shout") + " ";
break;
- case CHAT_TYPE_DEBUG_MSG:
case CHAT_TYPE_OWNER:
+ if (RlvActions::isRlvEnabled())
+ {
+ if (RlvHandler::instance().handleSimulatorChat(mesg, chat, chatter))
+ {
+ break;
+ }
+ else if (show_script_chat_particles)
+ {
+ LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
+ psc->setSourceObject(chatter);
+ psc->setColor(color);
+ //We set the particles to be owned by the object's owner,
+ //just in case they should be muted by the mute list
+ psc->setOwnerUUID(owner_id);
+ LLViewerPartSim::getInstance()->addPartSource(psc);
+ }
+ }
+ case CHAT_TYPE_DEBUG_MSG:
case CHAT_TYPE_NORMAL:
case CHAT_TYPE_DIRECT:
break;
- case CHAT_TYPE_SHOUT:
- chat.mText = LLTrans::getString("shout") + " ";
- break;
case CHAT_TYPE_START:
case CHAT_TYPE_STOP:
LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL;
@@ -2487,7 +2532,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
break;
}
- chat.mText += mesg;
+ chat.mText = prefix + msg_without_prefix;
}
// We have a real utterance now, so can stop showing "..." and proceed.
@@ -2568,6 +2613,11 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
msg_notify["from_id"] = chat.mFromID;
msg_notify["source_type"] = chat.mSourceType;
on_new_message(msg_notify);
+
+
+ msg_notify["chat_type"] = chat.mChatType;
+ msg_notify["message"] = mesg;
+ LLEventPumps::instance().obtain("LLNearbyChat").post(msg_notify);
}
}
@@ -2713,7 +2763,7 @@ public:
virtual ~LLPostTeleportNotifiers();
//function to be called at the supplied frequency
- virtual bool tick();
+ bool tick() override;
};
LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 )
@@ -3139,8 +3189,8 @@ void process_crossed_region(LLMessageSystem* msg, void**)
}
-// sends an AgentUpdate message to the server... or not:
-// only when force_send is 'true' OR
+// sends an AgentUpdate message to the server... or not
+// e.g. only when force_send is 'true' OR
// something changed AND the update is not being throttled
void send_agent_update(bool force_send, bool send_reliable)
{
@@ -3206,8 +3256,6 @@ void send_agent_update(bool force_send, bool send_reliable)
return;
}
- bool send_update = force_send || sec_since_last_send > MAX_AGENT_UPDATE_PERIOD;
-
LLVector3 camera_pos_agent = gAgentCamera.getCameraPositionAgent(); // local to avatar's region
LLVector3 camera_at = LLViewerCamera::getInstance()->getAtAxis();
LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion();
@@ -3224,6 +3272,7 @@ void send_agent_update(bool force_send, bool send_reliable)
flags |= AU_FLAGS_CLIENT_AUTOPILOT;
}
+ bool send_update = force_send || sec_since_last_send > MAX_AGENT_UPDATE_PERIOD;
if (!send_update)
{
// check to see if anything changed
@@ -6610,7 +6659,6 @@ void process_initiate_download(LLMessageSystem* msg, void**)
(void**)new std::string(viewer_filename));
}
-
void process_script_teleport_request(LLMessageSystem* msg, void**)
{
if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return;
@@ -6624,6 +6672,11 @@ void process_script_teleport_request(LLMessageSystem* msg, void**)
msg->getString("Data", "SimName", sim_name);
msg->getVector3("Data", "SimPosition", pos);
msg->getVector3("Data", "LookAt", look_at);
+ U32 flags = (BEACON_SHOW_MAP | BEACON_FOCUS_MAP);
+ if (msg->has("Options"))
+ {
+ msg->getU32("Options", "Flags", flags);
+ }
LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance();
if(instance)
@@ -6634,7 +6687,13 @@ void process_script_teleport_request(LLMessageSystem* msg, void**)
<< LL_ENDL;
instance->trackURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]);
- LLFloaterReg::showInstance("world_map", "center");
+ if (flags & BEACON_SHOW_MAP)
+ {
+ bool old_auto_focus = instance->getAutoFocus();
+ instance->setAutoFocus(flags & BEACON_FOCUS_MAP);
+ instance->openFloater("center");
+ instance->setAutoFocus(old_auto_focus);
+ }
}
// remove above two lines and replace with below line
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 41b2c4b44b..7741f1fbe7 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2325,6 +2325,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
// Set the rotation of the object followed by adjusting for the accumulated angular velocity (llSetTargetOmega)
setRotation(new_rot * mAngularVelocityRot);
+ if ((mFlags & FLAGS_SERVER_AUTOPILOT) && asAvatar() && asAvatar()->isSelf())
+ {
+ gAgent.resetAxes();
+ gAgent.rotate(new_rot);
+ gAgentCamera.resetView();
+ }
setChanged(ROTATED | SILHOUETTE);
}
@@ -5235,8 +5241,7 @@ void LLViewerObject::updateTEMaterialTextures(U8 te)
LLUUID mat_id = getRenderMaterialID(te);
if (mat == nullptr && mat_id.notNull())
{
- mat = (LLFetchedGLTFMaterial*) gGLTFMaterialList.getMaterial(mat_id);
- llassert(mat == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(gGLTFMaterialList.getMaterial(mat_id)) != nullptr);
+ mat = gGLTFMaterialList.getMaterial(mat_id);
if (mat->isFetching())
{ // material is not loaded yet, rebuild draw info when the object finishes loading
mat->onMaterialComplete([id=getID()]
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 9e1d86faac..6167129077 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -65,6 +65,7 @@
#include "lltoolmgr.h"
#include "lltoolpie.h"
#include "llkeyboard.h"
+#include "llmeshrepository.h"
#include "u64.h"
#include "llviewertexturelist.h"
#include "lldatapacker.h"
@@ -1419,6 +1420,10 @@ void LLViewerObjectList::cleanDeadObjects(bool use_timer)
// No dead objects, don't need to scan object list.
return;
}
+ if ((LLApp::isExiting()) || (mNumDeadObjects == (S32)mObjects.size()))
+ {
+ gMeshRepo.unregisterAllMeshes();
+ }
LL_PROFILE_ZONE_SCOPED;
diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h
index 96b569f126..9759cf6a17 100644
--- a/indra/newview/llviewerparcelmediaautoplay.h
+++ b/indra/newview/llviewerparcelmediaautoplay.h
@@ -35,7 +35,7 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton<LLViewerPar
{
LLSINGLETON(LLViewerParcelMediaAutoPlay);
public:
- virtual bool tick() override;
+ bool tick() override;
static void playStarted();
private:
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index 2e9b5de72b..a643aa91bb 100755
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -33,6 +33,7 @@
#include "llfloaterreg.h"
#include "llgl.h"
#include "llrender.h"
+#include "lluicolor.h"
#include "v4color.h"
#include "v2math.h"
@@ -50,8 +51,8 @@
#include "pipeline.h"
-static const U8 OVERLAY_IMG_COMPONENTS = 4;
-static const F32 LINE_WIDTH = 0.0625f;
+static constexpr U8 OVERLAY_IMG_COMPONENTS = 4;
+static constexpr F32 LINE_WIDTH = 0.0625f;
bool LLViewerParcelOverlay::sColorSetInitialized = false;
LLUIColor LLViewerParcelOverlay::sAvailColor;
@@ -62,9 +63,9 @@ LLUIColor LLViewerParcelOverlay::sForSaleColor;
LLUIColor LLViewerParcelOverlay::sAuctionColor;
LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters)
-: mRegion( region ),
- mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ),
- mDirty( false ),
+: mRegion(region),
+ mParcelGridsPerEdge(S32(region_width_meters / PARCEL_GRID_STEP_METERS)),
+ mDirty(false),
mTimeSinceLastUpdate(),
mOverlayTextureIdx(-1)
{
@@ -91,7 +92,7 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_
// Initialize the GL texture with empty data.
//
// Create the base texture.
- U8 *raw = mImageRaw->getData();
+ U8* raw = mImageRaw->getData();
const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge * OVERLAY_IMG_COMPONENTS;
for (S32 i = 0; i < COUNT; i++)
{
@@ -158,10 +159,10 @@ bool LLViewerParcelOverlay::encroachesOwned(const std::vector<LLBBox>& boxes) co
LLVector3 min = boxes[i].getMinAgent();
LLVector3 max = boxes[i].getMaxAgent();
- S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
for (S32 row = top; row <= bottom; row++)
{
@@ -186,10 +187,10 @@ bool LLViewerParcelOverlay::encroachesOnUnowned(const std::vector<LLBBox>& boxes
LLVector3 min = boxes[i].getMinAgent();
LLVector3 max = boxes[i].getMaxAgent();
- S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 top = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 bottom = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
for (S32 row = top; row <= bottom; row++)
{
@@ -223,10 +224,10 @@ bool LLViewerParcelOverlay::encroachesOnNearbyParcel(const std::vector<LLBBox>&
return true;
}
- S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 bottom = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
- S32 top = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1));
+ S32 left = S32(llclamp((min.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 right = S32(llclamp((max.mV[VX] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 bottom = S32(llclamp((min.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
+ S32 top = S32(llclamp((max.mV[VY] / PARCEL_GRID_STEP_METERS), 0.f, REGION_WIDTH_METERS - 1.f));
const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
@@ -348,11 +349,11 @@ void LLViewerParcelOverlay::updateOverlayTexture()
const LLColor4U auction = sAuctionColor.get();
// Create the base texture.
- U8 *raw = mImageRaw->getData();
+ U8* raw = mImageRaw->getData();
const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge;
S32 max = mOverlayTextureIdx + mParcelGridsPerEdge;
if (max > COUNT) max = COUNT;
- S32 pixel_index = mOverlayTextureIdx*OVERLAY_IMG_COMPONENTS;
+ S32 pixel_index = mOverlayTextureIdx * OVERLAY_IMG_COMPONENTS;
S32 i;
for (i = mOverlayTextureIdx; i < max; i++)
{
@@ -361,7 +362,7 @@ void LLViewerParcelOverlay::updateOverlayTexture()
U8 r,g,b,a;
// Color stored in low three bits
- switch( ownership & 0x7 )
+ switch (ownership & 0x7)
{
case PARCEL_PUBLIC:
r = avail.mV[VRED];
@@ -407,10 +408,10 @@ void LLViewerParcelOverlay::updateOverlayTexture()
break;
}
- raw[pixel_index + 0] = (U8)r;
- raw[pixel_index + 1] = (U8)g;
- raw[pixel_index + 2] = (U8)b;
- raw[pixel_index + 3] = (U8)a;
+ raw[pixel_index + VRED] = (U8)r;
+ raw[pixel_index + VGREEN] = (U8)g;
+ raw[pixel_index + VBLUE] = (U8)b;
+ raw[pixel_index + VALPHA] = (U8)a;
pixel_index += OVERLAY_IMG_COMPONENTS;
}
@@ -431,11 +432,10 @@ void LLViewerParcelOverlay::updateOverlayTexture()
}
}
-
-void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay)
+void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8* packed_overlay)
{
// Unpack the message data into the ownership array
- S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
+ S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge;
S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS;
memcpy(mOwnership + chunk*chunk_size, packed_overlay, chunk_size); /*Flawfinder: ignore*/
@@ -460,16 +460,16 @@ void LLViewerParcelOverlay::updatePropertyLines()
mEdges.clear();
- const F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
+ constexpr F32 GRID_STEP = PARCEL_GRID_STEP_METERS;
const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
for (S32 row = 0; row < GRIDS_PER_EDGE; row++)
{
for (S32 col = 0; col < GRIDS_PER_EDGE; col++)
{
- U8 overlay = mOwnership[row*GRIDS_PER_EDGE+col];
+ U8 overlay = mOwnership[row * GRIDS_PER_EDGE + col];
S32 colorIndex = overlay & PARCEL_COLOR_MASK;
- switch(colorIndex)
+ switch (colorIndex)
{
case PARCEL_SELF:
case PARCEL_GROUP:
@@ -483,11 +483,11 @@ void LLViewerParcelOverlay::updatePropertyLines()
const LLColor4U& color = colors[colorIndex];
- F32 left = col*GRID_STEP;
- F32 right = left+GRID_STEP;
+ F32 left = col * GRID_STEP;
+ F32 right = left + GRID_STEP;
- F32 bottom = row*GRID_STEP;
- F32 top = bottom+GRID_STEP;
+ F32 bottom = row * GRID_STEP;
+ F32 top = bottom + GRID_STEP;
// West edge
if (overlay & PARCEL_WEST_LINE)
@@ -528,99 +528,123 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3
Edge& edge = mEdges.back();
edge.color = color;
+ // Detailized rendering vertices:
+ // A B C D E F G
+ // *-*------*--------*--------*------*-* : 'outside' vertices are placed right on the border
+ // *------*--------*--------*------* : 'inside' vertices are shifted on LINE_WIDTH inside
+
+ // Simplified rendering vertices:
+ // A G
+ // *-----------------------------------*
+ // *-----------------------------------*
+
F32 outside_x = start_x;
F32 outside_y = start_y;
- F32 outside_z = 0.f;
- F32 inside_x = start_x + tick_dx;
- F32 inside_y = start_y + tick_dy;
- F32 inside_z = 0.f;
+ F32 outside_z = land.resolveHeightRegion(outside_x, outside_y);
+ F32 inside_x = start_x + tick_dx;
+ F32 inside_y = start_y + tick_dy;
+ F32 inside_z = land.resolveHeightRegion(inside_x, inside_y);
+
+ auto move = [&](F32 distance)
+ {
+ outside_x += dx * distance;
+ outside_y += dy * distance;
+ outside_z = land.resolveHeightRegion(outside_x, outside_y);
+ inside_x += dx * distance;
+ inside_y += dy * distance;
+ inside_z = land.resolveHeightRegion(inside_x, inside_y);
+ };
- auto split = [&](const LLVector3& start, F32 x, F32 y, F32 z, F32 part)
+ auto split = [&](U32 lod, const LLVector4a& start, F32 x, F32 y, F32 z, F32 part)
{
- F32 new_x = start.mV[0] + (x - start.mV[0]) * part;
- F32 new_y = start.mV[1] + (y - start.mV[1]) * part;
- F32 new_z = start.mV[2] + (z - start.mV[2]) * part;
- edge.vertices.emplace_back(new_x, new_y, new_z);
+ F32 new_x = start[VX] + (x - start[VX]) * part;
+ F32 new_y = start[VY] + (y - start[VY]) * part;
+ F32 new_z = start[VZ] + (z - start[VZ]) * part;
+ edge.pushVertex(lod, new_x, new_y, new_z, water_z);
};
- auto checkForSplit = [&]()
+ auto checkForSplit = [&](U32 lod)
{
- const LLVector3& last_outside = edge.vertices.back();
- F32 z0 = last_outside.mV[2];
+ const std::vector<LLVector4a>& vertices = edge.verticesUnderWater[lod];
+ const LLVector4a& last_outside = vertices.back();
+ F32 z0 = last_outside[VZ];
F32 z1 = outside_z;
if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z))
return;
F32 part = (water_z - z0) / (z1 - z0);
- const LLVector3& last_inside = edge.vertices[edge.vertices.size() - 2];
- split(last_inside, inside_x, inside_y, inside_z, part);
- split(last_outside, outside_x, outside_y, outside_z, part);
+ const LLVector4a& last_inside = vertices[vertices.size() - 2];
+ split(lod, last_inside, inside_x, inside_y, inside_z, part);
+ split(lod, last_outside, outside_x, outside_y, outside_z, part);
};
- // First part, only one vertex
- outside_z = land.resolveHeightRegion( outside_x, outside_y );
-
- edge.vertices.emplace_back(outside_x, outside_y, outside_z);
-
- inside_x += dx * LINE_WIDTH;
- inside_y += dy * LINE_WIDTH;
-
- outside_x += dx * LINE_WIDTH;
- outside_y += dy * LINE_WIDTH;
-
- // Then the "actual edge"
- inside_z = land.resolveHeightRegion( inside_x, inside_y );
- outside_z = land.resolveHeightRegion( outside_x, outside_y );
+ auto pushTwoVertices = [&](U32 lod)
+ {
+ LLVector3 out(outside_x, outside_y, outside_z);
+ LLVector3 in(inside_x, inside_y, inside_z);
+ if (fabs(inside_z - outside_z) < LINE_WIDTH / 5)
+ {
+ edge.pushVertex(lod, inside_x, inside_y, inside_z, water_z);
+ }
+ else
+ {
+ // Make the line thinner if heights differ too much
+ LLVector3 dist(in - out);
+ F32 coef = dist.length() / LINE_WIDTH;
+ LLVector3 new_in(out + dist / coef);
+ edge.pushVertex(lod, new_in[VX], new_in[VY], new_in[VZ], water_z);
+ }
+ edge.pushVertex(lod, outside_x, outside_y, outside_z, water_z);
+ };
- edge.vertices.emplace_back(inside_x, inside_y, inside_z);
- edge.vertices.emplace_back(outside_x, outside_y, outside_z);
+ // Point A simplified (first two vertices)
+ pushTwoVertices(1);
- inside_x += dx * (dx - LINE_WIDTH);
- inside_y += dy * (dy - LINE_WIDTH);
+ // Point A detailized (only one vertex)
+ edge.pushVertex(0, outside_x, outside_y, outside_z, water_z);
- outside_x += dx * (dx - LINE_WIDTH);
- outside_y += dy * (dy - LINE_WIDTH);
+ // Point B (two vertices)
+ move(LINE_WIDTH);
+ pushTwoVertices(0);
- // Middle part, full width
- const S32 GRID_STEP = S32( PARCEL_GRID_STEP_METERS );
- for (S32 i = 1; i < GRID_STEP; i++)
+ // Points C, D, E
+ F32 distance = 1.f - LINE_WIDTH;
+ constexpr U32 GRID_STEP = (U32)PARCEL_GRID_STEP_METERS;
+ for (U32 i = 1; i < GRID_STEP; ++i)
{
- inside_z = land.resolveHeightRegion( inside_x, inside_y );
- outside_z = land.resolveHeightRegion( outside_x, outside_y );
-
- checkForSplit();
-
- edge.vertices.emplace_back(inside_x, inside_y, inside_z);
- edge.vertices.emplace_back(outside_x, outside_y, outside_z);
-
- inside_x += dx;
- inside_y += dy;
-
- outside_x += dx;
- outside_y += dy;
+ move(distance);
+ checkForSplit(0);
+ pushTwoVertices(0);
+ distance = 1.f;
}
- // Extra buffer for edge
- inside_x -= dx * LINE_WIDTH;
- inside_y -= dy * LINE_WIDTH;
-
- outside_x -= dx * LINE_WIDTH;
- outside_y -= dy * LINE_WIDTH;
-
- inside_z = land.resolveHeightRegion( inside_x, inside_y );
- outside_z = land.resolveHeightRegion( outside_x, outside_y );
+ // Point F (two vertices)
+ move(1.f - LINE_WIDTH);
+ checkForSplit(0);
+ pushTwoVertices(0);
- checkForSplit();
+ // Point G simplified (last two vertices)
+ move(LINE_WIDTH);
+ checkForSplit(1);
+ pushTwoVertices(1);
- edge.vertices.emplace_back(inside_x, inside_y, inside_z);
- edge.vertices.emplace_back(outside_x, outside_y, outside_z);
-
- outside_x += dx * LINE_WIDTH;
- outside_y += dy * LINE_WIDTH;
+ // Point G detailized (only one vertex)
+ edge.pushVertex(0, outside_x, outside_y, outside_z, water_z);
+}
- // Last edge is not drawn to the edge
- outside_z = land.resolveHeightRegion( outside_x, outside_y );
+void LLViewerParcelOverlay::Edge::pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z)
+{
+ verticesUnderWater[lod].emplace_back(x, y, z);
+ gGL.transform(verticesUnderWater[lod].back());
- edge.vertices.emplace_back(outside_x, outside_y, outside_z);
+ if (z >= water_z)
+ {
+ verticesAboveWater[lod].push_back(verticesUnderWater[lod].back());
+ }
+ else
+ {
+ verticesAboveWater[lod].emplace_back(x, y, water_z);
+ gGL.transform(verticesAboveWater[lod].back());
+ }
}
void LLViewerParcelOverlay::setDirty()
@@ -666,7 +690,9 @@ void LLViewerParcelOverlay::renderPropertyLines()
return;
LLSurface& land = mRegion->getLand();
- F32 water_z = land.getWaterHeight() + 0.01f;
+
+ bool render_water = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER);
+ F32 water_z = render_water ? land.getWaterHeight() + 0.01f : 0;
LLGLSUIDefault gls_ui; // called from pipeline
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -700,6 +726,8 @@ void LLViewerParcelOverlay::renderPropertyLines()
// Stomp the camera into two dimensions
LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() );
+ bool draw_underwater = camera_region.mV[VZ] < water_z ||
+ !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER);
// Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind
// the camera. The cull plane normal is the camera's at axis.
@@ -707,15 +735,23 @@ void LLViewerParcelOverlay::renderPropertyLines()
cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS;
cull_plane_point += camera_region;
- bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build");
+ bool render_hidden = !draw_underwater &&
+ LLSelectMgr::sRenderHiddenSelections &&
+ LLFloaterReg::instanceVisible("build");
- const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f;
+ constexpr F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f;
+ constexpr F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25.f;
for (const Edge& edge : mEdges)
{
- LLVector3 center = edge.vertices[edge.vertices.size() >> 1];
-
- if (dist_vec_squared2D(center, camera_region) > PROPERTY_LINE_CLIP_DIST_SQUARED)
+ const std::vector<LLVector4a>& vertices0 = edge.verticesAboveWater[0];
+ const F32* first = vertices0.front().getF32ptr();
+ const F32* last = vertices0.back().getF32ptr();
+ LLVector3 center((first[VX] + last[VX]) / 2, (first[VY] + last[VY]) / 2, (first[VZ] + last[VZ]) / 2);
+ gGL.untransform(center);
+
+ F32 dist_squared = dist_vec_squared(center, camera_region);
+ if (dist_squared > PROPERTY_LINE_CLIP_DIST_SQUARED)
{
continue;
}
@@ -729,43 +765,33 @@ void LLViewerParcelOverlay::renderPropertyLines()
continue;
}
+ U32 lod = dist_squared < PROPERTY_LINE_LOD0_DIST_SQUARED ? 0 : 1;
+
gGL.begin(LLRender::TRIANGLE_STRIP);
gGL.color4ubv(edge.color.mV);
- for (const LLVector3& vertex : edge.vertices)
+ if (draw_underwater)
{
- if (render_hidden || camera_z < water_z || vertex.mV[2] >= water_z)
- {
- gGL.vertex3fv(vertex.mV);
- }
- else
- {
- LLVector3 visible = vertex;
- visible.mV[2] = water_z;
- gGL.vertex3fv(visible.mV);
- }
+ gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]);
}
-
- gGL.end();
-
- if (render_hidden)
+ else
{
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
+ gGL.vertexBatchPreTransformed(edge.verticesAboveWater[lod]);
- gGL.begin(LLRender::TRIANGLE_STRIP);
+ if (render_hidden)
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
- LLColor4U color = edge.color;
- color.mV[3] /= 4;
- gGL.color4ubv(color.mV);
+ LLColor4U color = edge.color;
+ color.mV[VALPHA] /= 4;
+ gGL.color4ubv(color.mV);
- for (const LLVector3& vertex : edge.vertices)
- {
- gGL.vertex3fv(vertex.mV);
+ gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]);
}
-
- gGL.end();
}
+
+ gGL.end();
}
gGL.popMatrix();
@@ -790,7 +816,7 @@ void grid_2d_part_lines(const F32 left, const F32 top, const F32 right, const F3
gGL.end();
}
-void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32 *parcel_outline_color)
+void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color)
{
static LLCachedControl<bool> show(gSavedSettings, "MiniMapShowPropertyLines");
@@ -801,8 +827,8 @@ void LLViewerParcelOverlay::renderPropertyLinesOnMinimap(F32 scale_pixels_per_me
LLVector3 origin_agent = mRegion->getOriginAgent();
LLVector3 rel_region_pos = origin_agent - gAgentCamera.getCameraPositionAgent();
- F32 region_left = rel_region_pos.mV[0] * scale_pixels_per_meter;
- F32 region_bottom = rel_region_pos.mV[1] * scale_pixels_per_meter;
+ F32 region_left = rel_region_pos.mV[VX] * scale_pixels_per_meter;
+ F32 region_bottom = rel_region_pos.mV[VY] * scale_pixels_per_meter;
F32 map_parcel_width = PARCEL_GRID_STEP_METERS * scale_pixels_per_meter;
const S32 GRIDS_PER_EDGE = mParcelGridsPerEdge;
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index 03ae464cb8..7271c85701 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -34,12 +34,11 @@
#include "llframetimer.h"
#include "lluuid.h"
#include "llviewertexture.h"
-#include "llgl.h"
-#include "lluicolor.h"
class LLViewerRegion;
class LLVector3;
class LLColor4U;
+class LLUIColor;
class LLVector2;
class LLViewerParcelOverlay : public LLGLUpdate
@@ -65,19 +64,18 @@ public:
bool isSoundLocal(const LLVector3& pos) const;
- bool isBuildCameraAllowed(const LLVector3& pos) const;
F32 getOwnedRatio() const;
// Returns the number of vertices drawn
void renderPropertyLines();
void renderPropertyLinesOnMinimap(F32 scale_pixels_per_meter, const F32* parcel_outline_color);
- U8 ownership( const LLVector3& pos) const;
- U8 parcelLineFlags( const LLVector3& pos) const;
+ U8 ownership(const LLVector3& pos) const;
+ U8 parcelLineFlags(const LLVector3& pos) const;
U8 parcelLineFlags(S32 row, S32 col) const;
// MANIPULATE
- void uncompressLandOverlay(S32 chunk, U8 *compressed_overlay);
+ void uncompressLandOverlay(S32 chunk, U8* compressed_overlay);
// Indicate property lines and overlay texture need to be rebuilt.
void setDirty();
@@ -88,8 +86,7 @@ public:
private:
// This is in parcel rows and columns, not grid rows and columns
// Stored in bottom three bits.
- U8 ownership(S32 row, S32 col) const
- { return parcelFlags(row, col, (U8)0x7); }
+ U8 ownership(S32 row, S32 col) const { return parcelFlags(row, col, (U8)0x7); }
U8 parcelFlags(S32 row, S32 col, U8 flags) const;
@@ -119,7 +116,10 @@ private:
struct Edge
{
- std::vector<LLVector3> vertices;
+ void pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z);
+ // LOD: 0 - detailized, 1 - simplified
+ std::vector<LLVector4a> verticesAboveWater[2];
+ std::vector<LLVector4a> verticesUnderWater[2];
LLColor4U color;
};
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 03d5563c65..739821d2f5 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -38,7 +38,6 @@
#include "llregionhandle.h"
#include "llsurface.h"
#include "message.h"
-//#include "vmath.h"
#include "v3math.h"
#include "v4math.h"
@@ -3156,7 +3155,7 @@ void LLViewerRegion::unpackRegionHandshake()
std::string cap = getCapability("ModifyRegion"); // needed for queueQuery
if (cap.empty())
{
- LLFloaterRegionInfo::sRefreshFromRegion(this);
+ LLFloaterRegionInfo::refreshFromRegion(this);
}
else
{
@@ -3168,7 +3167,7 @@ void LLViewerRegion::unpackRegionHandshake()
LLVLComposition* compp = region->getComposition();
if (!compp) { return; }
compp->apply(composition_changes);
- LLFloaterRegionInfo::sRefreshFromRegion(region);
+ LLFloaterRegionInfo::refreshFromRegion(region);
});
}
}
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 58b541b19b..a6d397c039 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -37,7 +37,6 @@
#include "llrender.h"
#include "llenvironment.h"
#include "llerrorcontrol.h"
-#include "llatmosphere.h"
#include "llworld.h"
#include "llsky.h"
@@ -101,6 +100,7 @@ LLGLSLShader gReflectionProbeDisplayProgram;
LLGLSLShader gCopyProgram;
LLGLSLShader gCopyDepthProgram;
LLGLSLShader gPBRTerrainBakeProgram;
+LLGLSLShader gTerrainStampProgram;
//object shaders
LLGLSLShader gObjectPreviewProgram;
@@ -731,14 +731,6 @@ std::string LLViewerShaderMgr::loadBasicShaders()
S32 sum_lights_class = 3;
-#if LL_DARWIN
- // Work around driver crashes on older Macs when using deferred rendering
- // NORSPEC-59
- //
- if (gGLManager.mIsMobileGF)
- sum_lights_class = 3;
-#endif
-
// Use the feature table to mask out the max light level to use. Also make sure it's at least 1.
S32 max_light_class = gSavedSettings.getS32("RenderShaderLightingMaxLevel");
sum_lights_class = llclamp(sum_lights_class, 1, max_light_class);
@@ -3179,6 +3171,34 @@ bool LLViewerShaderMgr::loadShadersInterface()
}
}
+ if (gSavedSettings.getBOOL("LocalTerrainPaintEnabled"))
+ {
+ if (success)
+ {
+ LLGLSLShader* shader = &gTerrainStampProgram;
+ U32 bit_depth = gSavedSettings.getU32("TerrainPaintBitDepth");
+ // LLTerrainPaintMap currently uses an RGB8 texture internally
+ bit_depth = llclamp(bit_depth, 1, 8);
+ shader->mName = llformat("Terrain Stamp Shader RGB%o", bit_depth);
+
+ shader->mShaderFiles.clear();
+ shader->mShaderFiles.push_back(make_pair("interface/terrainStampV.glsl", GL_VERTEX_SHADER));
+ shader->mShaderFiles.push_back(make_pair("interface/terrainStampF.glsl", GL_FRAGMENT_SHADER));
+ shader->mShaderLevel = mShaderLevel[SHADER_INTERFACE];
+ const U32 value_range = (1 << bit_depth) - 1;
+ shader->addPermutation("TERRAIN_PAINT_PRECISION", llformat("%d", value_range));
+ success = success && shader->createShader();
+ //llassert(success);
+ if (!success)
+ {
+ LL_WARNS() << "Failed to create shader '" << shader->mName << "', disabling!" << LL_ENDL;
+ gSavedSettings.setBOOL("RenderCanUseTerrainBakeShaders", false);
+ // continue as if this shader never happened
+ success = true;
+ }
+ }
+ }
+
if (success)
{
gAlphaMaskProgram.mName = "Alpha Mask Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index b08796025a..e654967c46 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -175,6 +175,7 @@ extern LLGLSLShader gReflectionProbeDisplayProgram;
extern LLGLSLShader gCopyProgram;
extern LLGLSLShader gCopyDepthProgram;
extern LLGLSLShader gPBRTerrainBakeProgram;
+extern LLGLSLShader gTerrainStampProgram;
//output tex0[tc0] - tex1[tc1]
extern LLGLSLShader gTwoTextureCompareProgram;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index ad503cbac7..a4b06b1e1a 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -66,6 +66,8 @@
#include "llinventorymodel.h"
#include "lluiusage.h"
#include "lltranslate.h"
+#include "llluamanager.h"
+#include "scope_exit.h"
// "Minimal Vulkan" to get max API Version
@@ -509,7 +511,6 @@ void send_viewer_stats(bool include_preferences)
return;
}
- LLSD body;
std::string url = gAgent.getRegion()->getCapability("ViewerStats");
if (url.empty()) {
@@ -517,8 +518,18 @@ void send_viewer_stats(bool include_preferences)
return;
}
- LLViewerStats::instance().getRecording().pause();
+ LLSD body = capture_viewer_stats(include_preferences);
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
+ "Statistics posted to sim", "Failed to post statistics to sim");
+}
+
+LLSD capture_viewer_stats(bool include_preferences)
+{
+ LLViewerStats& vstats{ LLViewerStats::instance() };
+ vstats.getRecording().pause();
+ LL::scope_exit cleanup([&vstats]{ vstats.getRecording().resume(); });
+ LLSD body;
LLSD &agent = body["agent"];
time_t ltime;
@@ -620,6 +631,10 @@ void send_viewer_stats(bool include_preferences)
system["shader_level"] = shader_level;
+ LLSD &scripts = body["scripts"];
+ scripts["lua_scripts"] = LLLUAmanager::sScriptCount;
+ scripts["lua_auto_scripts"] = LLLUAmanager::sAutorunScriptCount;
+
LLSD &download = body["downloads"];
download["world_kbytes"] = F64Kilobytes(gTotalWorldData).value();
@@ -776,7 +791,7 @@ void send_viewer_stats(bool include_preferences)
LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL;
// <ND> Do those lines even do anything sane in regard of debug logging?
- LL_DEBUGS("LogViewerStatsPacket");
+ LL_DEBUGS("LogViewerStatsPacket") << " ";
std::string filename("viewer_stats_packet.xml");
llofstream of(filename.c_str());
LLSDSerialize::toPrettyXML(body,of);
@@ -786,10 +801,7 @@ void send_viewer_stats(bool include_preferences)
body["session_id"] = gAgentSessionID;
LLViewerStats::getInstance()->addToMessage(body);
-
- LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
- "Statistics posted to sim", "Failed to post statistics to sim");
- LLViewerStats::instance().getRecording().resume();
+ return body;
}
LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 8aed1c537e..dd66fee436 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -281,6 +281,7 @@ static const F32 SEND_STATS_PERIOD = 300.0f;
// The following are from (older?) statistics code found in appviewer.
void update_statistics();
+LLSD capture_viewer_stats(bool include_preferences);
void send_viewer_stats(bool include_preferences);
void update_texture_time();
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 0f9c65893d..6953407f75 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1070,6 +1070,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
mOrigHeight = 0;
mHasAux = false;
mNeedsAux = false;
+ mLastWorkerDiscardLevel = -1;
mRequestedDiscardLevel = -1;
mRequestedDownloadPriority = 0.f;
mFullyLoaded = false;
@@ -1222,12 +1223,11 @@ void LLViewerFetchedTexture::loadFromFastCache()
if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)
{
- S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS;
- S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS;
- if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height))
+ if (mRawImage && (mRawImage->getWidth() > DEFAULT_THUMBNAIL_DIMENSIONS || mRawImage->getHeight() > DEFAULT_THUMBNAIL_DIMENSIONS))
{
- // scale oversized icon, no need to give more work to gl
- mRawImage->scale(expected_width, expected_height);
+ // Scale oversized thumbnail
+ // thumbnails aren't supposed to go over DEFAULT_THUMBNAIL_DIMENSIONS
+ mRawImage->scale(DEFAULT_THUMBNAIL_DIMENSIONS, DEFAULT_THUMBNAIL_DIMENSIONS);
}
}
@@ -1904,13 +1904,10 @@ bool LLViewerFetchedTexture::updateFetch()
if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)
{
- S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS;
- S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS;
- if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height))
+ if (mRawImage && (mRawImage->getWidth() > DEFAULT_THUMBNAIL_DIMENSIONS || mRawImage->getHeight() > DEFAULT_THUMBNAIL_DIMENSIONS))
{
- // scale oversized icon, no need to give more work to gl
- // since we got mRawImage from thread worker and image may be in use (ex: writing cache), make a copy
- mRawImage = mRawImage->scaled(expected_width, expected_height);
+ // Scale oversized thumbnail
+ mRawImage = mRawImage->scaled(DEFAULT_THUMBNAIL_DIMENSIONS, DEFAULT_THUMBNAIL_DIMENSIONS);
}
}
@@ -2044,18 +2041,26 @@ bool LLViewerFetchedTexture::updateFetch()
}
// bypass texturefetch directly by pulling from LLTextureCache
- S32 fetch_request_discard = -1;
- fetch_request_discard = LLAppViewer::getTextureFetch()->createRequest(mFTType, mUrl, getID(), getTargetHost(), decode_priority,
- w, h, c, desired_discard, needsAux(), mCanUseHTTP);
+ S32 worker_discard = -1;
+ S32 result = LLAppViewer::getTextureFetch()->createRequest(mFTType, mUrl, getID(), getTargetHost(), decode_priority,
+ w, h, c, desired_discard, needsAux(), mCanUseHTTP, worker_discard);
+
- if (fetch_request_discard >= 0)
+ if ((result >= 0) // Worker created
+ // scaled and standard images share requests, they just process the result differently
+ // if mLastWorkerDiscardLevel doen't match worker, worker was requested by a different
+ // image and current one needs to schedule an update
+ || (result == LLTextureFetch::FETCH_REQUEST_EXISTS
+ && mLastWorkerDiscardLevel != worker_discard)
+ )
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - request created");
mHasFetcher = true;
mIsFetching = true;
+ mLastWorkerDiscardLevel = worker_discard;
// in some cases createRequest can modify discard, as an example
// bake textures are always at discard 0
- mRequestedDiscardLevel = llmin(desired_discard, fetch_request_discard);
+ mRequestedDiscardLevel = llmin(desired_discard, worker_discard);
mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP);
}
@@ -2667,11 +2672,9 @@ void LLViewerFetchedTexture::saveRawImage()
}
else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)
{
- S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS;
- S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS;
- if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)
+ if (mRawImage->getWidth() > DEFAULT_THUMBNAIL_DIMENSIONS || mRawImage->getHeight() > DEFAULT_THUMBNAIL_DIMENSIONS)
{
- mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents());
+ mSavedRawImage = new LLImageRaw(DEFAULT_THUMBNAIL_DIMENSIONS, DEFAULT_THUMBNAIL_DIMENSIONS, mRawImage->getComponents());
mSavedRawImage->copyScaled(mRawImage);
}
else
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 65fa633f81..c5dbbb82ef 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -439,6 +439,7 @@ protected:
bool mKnownDrawSizeChanged ;
std::string mUrl;
+ S32 mLastWorkerDiscardLevel;
S32 mRequestedDiscardLevel;
F32 mRequestedDownloadPriority;
S32 mFetchState;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 9379eed14a..47b247cee8 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -374,10 +374,31 @@ void LLViewerTextureList::shutdown()
mInitialized = false ; //prevent loading textures again.
}
+namespace
+{
+
+std::string tex_name_as_string(const LLViewerFetchedTexture* image)
+{
+ if (!image->getGLTexture()) { return std::string("N/A"); }
+ return std::to_string(image->getGLTexture()->getTexName());
+}
+
+const std::string& tex_label_as_string(const LLViewerFetchedTexture* image, std::string& label)
+{
+ bool error;
+ image->getGLObjectLabel(label, error);
+ if (error) { label.assign("N/A"); }
+ return label;
+}
+
+};
+
void LLViewerTextureList::dump()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL;
+ LL_INFOS() << __FUNCTION__ << "()" << LL_ENDL;
+
+ std::string label;
for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
{
LLViewerFetchedTexture* image = *it;
@@ -388,6 +409,9 @@ void LLViewerTextureList::dump()
<< " discard " << image->getDiscardLevel()
<< " desired " << image->getDesiredDiscardLevel()
<< " http://asset.siva.lindenlab.com/" << image->getID() << ".texture"
+ << " faces " << image->getTotalNumFaces()
+ << " texname " << tex_name_as_string(image)
+ << " label \"" << tex_label_as_string(image, label) << "\""
<< LL_ENDL;
}
}
@@ -432,7 +456,12 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
std::string url = "file://" + full_path;
- return getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id);
+ LLViewerFetchedTexture* tex = getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id);
+ if (gDebugTextureLabelLocalFilesSession)
+ {
+ gTextureList.mNameTextureList.push_back(LLViewerTextureList::NameElement(tex, filename));
+ }
+ return tex;
}
LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url,
@@ -854,6 +883,10 @@ void LLViewerTextureList::updateImages(F32 max_time)
//handle results from decode threads
updateImagesCreateTextures(remaining_time);
+ // Label all images (if enabled)
+ updateImagesNameTextures();
+ labelAll();
+
bool didone = false;
for (image_list_t::iterator iter = mCallbackList.begin();
iter != mCallbackList.end(); )
@@ -974,7 +1007,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
// this is an alternative to decaying mMaxVirtualSize over time
// that keeps textures from continously downrezzing and uprezzing in the background
- if (LLViewerTexture::sDesiredDiscardBias > 1.5f ||
+ if (LLViewerTexture::sDesiredDiscardBias > 1.5f ||
(!on_screen && LLViewerTexture::sDesiredDiscardBias > 1.f))
{
imagep->mMaxVirtualSize = 0.f;
@@ -1123,6 +1156,75 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
return create_timer.getElapsedTimeF32();
}
+void LLViewerTextureList::updateImagesNameTextures()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ if (gGLManager.mIsDisabled) { return; }
+ static LLCachedControl<bool> debug_texture_label(gSavedSettings, "RenderDebugTextureLabel", false);
+ if (!debug_texture_label()) { return; }
+
+#ifndef LL_DARWIN
+ static GLsizei max_length = 0;
+ if (max_length == 0) { glGetIntegerv(GL_MAX_LABEL_LENGTH, &max_length); }
+#endif
+
+ auto it = mNameTextureList.begin();
+ while (it != mNameTextureList.end()) // For ALL textures needing names
+ {
+ LLViewerFetchedTexture* tex = it->mTex;
+ // Check that the texture is in the list first (otherwise it may be a dead pointer)
+ // A raw pointer ensures textures are cleaned up when this code isn't running.
+ const bool alive = mImageList.find(tex) != mImageList.end();
+
+ if (alive)
+ {
+ if (tex->hasGLTexture())
+ {
+ if(tex->getTexName())
+ {
+ tex->setGLObjectLabel(it->mPrefix, true);
+ it = mNameTextureList.erase(it); // Assume no rename needed
+ }
+ else
+ {
+ ++it; // Not ready
+ }
+ }
+ else
+ {
+ ++it; // Not ready
+ }
+ }
+ else
+ {
+ it = mNameTextureList.erase(it); // Remove dead pointer
+ }
+ }
+}
+
+void LLViewerTextureList::labelAll()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ static LLCachedControl<bool> debug_texture_label(gSavedSettings, "RenderDebugTextureLabel", false);
+ if (!debug_texture_label()) { return; }
+
+ static const std::string local_prefix = "lltexlocal";
+ static const std::string other_prefix = "lltexother";
+
+ std::string label;
+ bool error;
+ for (LLViewerFetchedTexture* image : mImageList)
+ {
+ image->getGLObjectLabel(label, error);
+ if (!error && label.empty())
+ {
+ const S32 category = image->getGLTexture()->getCategory();
+ const std::string& new_prefix = category == LLGLTexture::LOCAL ? local_prefix : other_prefix;
+ image->setGLObjectLabel(new_prefix, true);
+ }
+ }
+}
+
F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
@@ -1305,6 +1407,10 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
max_time = llmax(max_time, .001f);
F32 create_time = updateImagesCreateTextures(max_time);
+ // Label all images (if enabled)
+ updateImagesNameTextures();
+ labelAll();
+
LL_DEBUGS("ViewerImages") << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. "
<< " fetch_pending " << fetch_pending
<< " create_time " << create_time
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index 7c7112f4cf..08dd2d0f7f 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -153,6 +153,9 @@ private:
void updateImagesUpdateStats();
F32 updateImagesLoadingFastCache(F32 max_time);
+ void updateImagesNameTextures();
+ void labelAll();
+
void addImage(LLViewerFetchedTexture *image, ETexListType tex_type);
void deleteImage(LLViewerFetchedTexture *image);
@@ -214,6 +217,14 @@ public:
// images that have been loaded but are waiting to be uploaded to GL
image_queue_t mCreateTextureList;
+ struct NameElement
+ {
+ NameElement(LLViewerFetchedTexture* tex, const std::string& prefix) : mTex(tex), mPrefix(prefix) {}
+ LLViewerFetchedTexture* mTex;
+ std::string mPrefix;
+ };
+ std::vector<NameElement> mNameTextureList;
+
// images that must be downscaled quickly so we don't run out of memory
image_queue_t mDownScaleQueue;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 2a21eeeb53..c51adaf115 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -66,6 +66,7 @@
#include "llchatentry.h"
#include "indra_constants.h"
#include "llassetstorage.h"
+#include "lldate.h"
#include "llerrorcontrol.h"
#include "llfontgl.h"
#include "llmousehandler.h"
@@ -195,7 +196,6 @@
#include "llviewerjoystick.h"
#include "llviewermenufile.h" // LLFilePickerReplyThread
#include "llviewernetwork.h"
-#include "llpostprocess.h"
#include "llfloaterimnearbychat.h"
#include "llagentui.h"
#include "llwearablelist.h"
@@ -1331,7 +1331,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
// Check the whitelist, if there's media (otherwise just show it)
if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
{
- if ( obj != mDragHoveredObject)
+ if (obj != mDragHoveredObject)
{
// Highlight the dragged object
LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
@@ -1425,10 +1425,16 @@ void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask
mWindow->showCursorFromMouseMove();
- if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME
- && !gDisconnected)
+ if (!gDisconnected)
{
- gAgent.clearAFK();
+ if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
+ {
+ gAgent.clearAFK();
+ }
+ else
+ {
+ gAwayTriggerTimer.reset();
+ }
}
}
@@ -1545,6 +1551,10 @@ bool LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, bool repeated)
{
gAgent.clearAFK();
}
+ else
+ {
+ gAwayTriggerTimer.reset();
+ }
// *NOTE: We want to interpret KEY_RETURN later when it arrives as
// a Unicode char, not as a keydown. Otherwise when client frame
@@ -3005,7 +3015,8 @@ bool LLViewerWindow::handleKey(KEY key, MASK mask)
{
if ((focusedFloaterName == "nearby_chat") || (focusedFloaterName == "im_container") || (focusedFloaterName == "impanel"))
{
- if (gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
+ LLCachedControl<bool> key_move(gSavedSettings, "ArrowKeysAlwaysMove");
+ if (key_move())
{
// let Control-Up and Control-Down through for chat line history,
if (!(key == KEY_UP && mask == MASK_CONTROL)
@@ -3019,10 +3030,9 @@ bool LLViewerWindow::handleKey(KEY key, MASK mask)
case KEY_RIGHT:
case KEY_UP:
case KEY_DOWN:
- case KEY_PAGE_UP:
- case KEY_PAGE_DOWN:
- case KEY_HOME:
- case KEY_END:
+ case KEY_PAGE_UP: //jump
+ case KEY_PAGE_DOWN: // down
+ case KEY_HOME: // toggle fly
// when chatbar is empty or ArrowKeysAlwaysMove set,
// pass arrow keys on to avatar...
return false;
@@ -3783,19 +3793,21 @@ void LLViewerWindow::updateUI()
void LLViewerWindow::updateLayout()
{
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
+ LLToolMgr* tool_mgr = LLToolMgr::getInstance();
+ LLTool* tool = tool_mgr->getCurrentTool();
+ LLCachedControl<bool> freeze_time(gSavedSettings, "FreezeTime");
if (gFloaterTools != NULL
&& tool != NULL
&& tool != gToolNull
&& tool != LLToolCompInspect::getInstance()
&& tool != LLToolDragAndDrop::getInstance()
- && !gSavedSettings.getBOOL("FreezeTime"))
+ && !freeze_time())
{
// Suppress the toolbox view if our source tool was the pie tool,
// and we've overridden to something else.
bool suppress_toolbox =
- (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) &&
- (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance());
+ (tool_mgr->getBaseTool() == LLToolPie::getInstance()) &&
+ (tool_mgr->getCurrentTool() != LLToolPie::getInstance());
LLMouseHandler *captor = gFocusMgr.getMouseCapture();
// With the null, inspect, or drag and drop tool, don't muck
@@ -3805,7 +3817,7 @@ void LLViewerWindow::updateLayout()
|| (tool != LLToolPie::getInstance() // not default tool
&& tool != LLToolCompGun::getInstance() // not coming out of mouselook
&& !suppress_toolbox // not override in third person
- && LLToolMgr::getInstance()->getCurrentToolset()->isShowFloaterTools()
+ && tool_mgr->getCurrentToolset()->isShowFloaterTools()
&& (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging
{
// Force floater tools to be visible (unless minimized)
@@ -4262,15 +4274,15 @@ void LLViewerWindow::pickAsync( S32 x,
bool pick_unselectable,
bool pick_reflection_probes)
{
+ static LLCachedControl<bool> select_invisible_objects(gSavedSettings, "SelectInvisibleObjects");
// "Show Debug Alpha" means no object actually transparent
bool in_build_mode = LLFloaterReg::instanceVisible("build");
- if (LLDrawPoolAlpha::sShowDebugAlpha
- || (in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")))
+ if (LLDrawPoolAlpha::sShowDebugAlpha || (in_build_mode && select_invisible_objects))
{
pick_transparent = true;
}
- LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, pick_unselectable, true, callback);
+ LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, false, pick_reflection_probes, true, pick_unselectable, callback);
schedulePick(pick_info);
}
@@ -4294,7 +4306,6 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
mWindow->delayInputProcessing();
}
-
void LLViewerWindow::performPick()
{
if (!mPicks.empty())
@@ -4328,8 +4339,9 @@ void LLViewerWindow::returnEmptyPicks()
// Performs the GL object/land pick.
LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transparent, bool pick_rigged, bool pick_particle, bool pick_unselectable, bool pick_reflection_probe)
{
+ static LLCachedControl<bool> select_invisible_objects(gSavedSettings, "SelectInvisibleObjects");
bool in_build_mode = LLFloaterReg::instanceVisible("build");
- if ((in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")) || LLDrawPoolAlpha::sShowDebugAlpha)
+ if ((in_build_mode && select_invisible_objects) || LLDrawPoolAlpha::sShowDebugAlpha)
{
// build mode allows interaction with all transparent objects
// "Show Debug Alpha" means no object actually transparent
@@ -4337,7 +4349,7 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, bool pick_transp
}
// shortcut queueing in mPicks and just update mLastPick in place
- MASK key_mask = gKeyboard->currentMask(true);
+ MASK key_mask = gKeyboard->currentMask(true);
mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, pick_rigged, pick_particle, pick_reflection_probe, true, false, NULL);
mLastPick.fetchResults();
@@ -4799,22 +4811,19 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save
}
// Look for an unused file name
- bool is_snapshot_name_loc_set = isSnapshotLocSet();
+ auto is_snapshot_name_loc_set = isSnapshotLocSet();
std::string filepath;
- S32 i = 1;
- S32 err = 0;
- std::string extension("." + image->getExtension());
+ auto i = 1;
+ auto err = 0;
+ auto extension("." + image->getExtension());
+ auto now = LLDate::now();
do
{
filepath = sSnapshotDir;
filepath += gDirUtilp->getDirDelimiter();
filepath += sSnapshotBaseName;
-
- if (is_snapshot_name_loc_set)
- {
- filepath += llformat("_%.3d",i);
- }
-
+ filepath += now.toLocalDateString("_%Y-%m-%d_%H%M%S");
+ filepath += llformat("%.2d", i);
filepath += extension;
llstat stat_info;
@@ -4858,7 +4867,7 @@ bool LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width,
LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL;
LLPointer<LLImageRaw> raw = new LLImageRaw;
- bool success = rawSnapshot(raw, image_width, image_height, true, false, show_ui, show_hud, do_rebuild);
+ bool success = rawSnapshot(raw, image_width, image_height, true, false, show_ui, show_hud, do_rebuild, 0, type);
if (success)
{
@@ -5767,11 +5776,6 @@ void LLViewerWindow::stopGL()
gBox.cleanupGL();
- if(gPostProcess)
- {
- gPostProcess->invalidate();
- }
-
gTextureList.destroyGL();
stop_glerror();
@@ -6057,14 +6061,14 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
bool pick_rigged,
bool pick_particle,
bool pick_reflection_probe,
- bool pick_uv_coords,
+ bool pick_surface_info,
bool pick_unselectable,
void (*pick_callback)(const LLPickInfo& pick_info))
: mMousePt(mouse_pos),
mKeyMask(keyboard_mask),
mPickCallback(pick_callback),
mPickType(PICK_INVALID),
- mWantSurfaceInfo(pick_uv_coords),
+ mWantSurfaceInfo(pick_surface_info),
mObjectFace(-1),
mUVCoords(-1.f, -1.f),
mSTCoords(-1.f, -1.f),
diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp
index da7e18af5c..45b4da0aac 100644
--- a/indra/newview/llviewerwindowlistener.cpp
+++ b/indra/newview/llviewerwindowlistener.cpp
@@ -35,6 +35,7 @@
// std headers
// external library headers
// other Linden headers
+#include "llcallbacklist.h"
#include "llviewerwindow.h"
LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow):
@@ -43,22 +44,12 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow):
mViewerWindow(llviewerwindow)
{
// add() every method we want to be able to invoke via this event API.
- LLSD saveSnapshotArgs;
- saveSnapshotArgs["filename"] = LLSD::String();
- saveSnapshotArgs["reply"] = LLSD::String();
- // The following are optional, so don't build them into required prototype.
-// saveSnapshotArgs["width"] = LLSD::Integer();
-// saveSnapshotArgs["height"] = LLSD::Integer();
-// saveSnapshotArgs["showui"] = LLSD::Boolean();
-// saveSnapshotArgs["showhud"] = LLSD::Boolean();
-// saveSnapshotArgs["rebuild"] = LLSD::Boolean();
-// saveSnapshotArgs["type"] = LLSD::String();
add("saveSnapshot",
- "Save screenshot: [\"filename\"], [\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n"
- "type: \"COLOR\", \"DEPTH\"\n"
- "Post on [\"reply\"] an event containing [\"ok\"]",
+ "Save screenshot: [\"filename\"] (extension may be specified: bmp, jpeg, png)\n"
+ "[\"width\"], [\"height\"], [\"showui\"], [\"showhud\"], [\"rebuild\"], [\"type\"]\n"
+ "type: \"COLOR\", \"DEPTH\"\n",
&LLViewerWindowListener::saveSnapshot,
- saveSnapshotArgs);
+ llsd::map("filename", LLSD::String(), "reply", LLSD()));
add("requestReshape",
"Resize the window: [\"w\"], [\"h\"]",
&LLViewerWindowListener::requestReshape);
@@ -71,7 +62,8 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const
#define tp(name) types[#name] = LLSnapshotModel::SNAPSHOT_TYPE_##name
tp(COLOR);
tp(DEPTH);
-#undef tp
+#undef tp
+
// Our add() call should ensure that the incoming LLSD does in fact
// contain our required arguments. Deal with the optional ones.
S32 width (mViewerWindow->getWindowWidthRaw());
@@ -94,14 +86,42 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const
TypeMap::const_iterator found = types.find(event["type"]);
if (found == types.end())
{
- LL_ERRS("LLViewerWindowListener") << "LLViewerWindowListener::saveSnapshot(): "
- << "unrecognized type " << event["type"] << LL_ENDL;
- return;
+ sendReply(llsd::map("error", stringize("Unrecognized type ", std::quoted(event["type"].asString()), " [\"COLOR\"] or [\"DEPTH\"] is expected.")), event);
+ return;
}
type = found->second;
}
- bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, showhud, rebuild, type);
- sendReply(LLSDMap("ok", ok), event);
+
+ std::string filename(event["filename"]);
+ if (filename.empty())
+ {
+ sendReply(llsd::map("error", stringize("File path is empty.")), event);
+ return;
+ }
+
+ LLSnapshotModel::ESnapshotFormat format(LLSnapshotModel::SNAPSHOT_FORMAT_BMP);
+ std::string ext = gDirUtilp->getExtension(filename);
+ if (ext.empty())
+ {
+ filename.append(".bmp");
+ }
+ else if (ext == "png")
+ {
+ format = LLSnapshotModel::SNAPSHOT_FORMAT_PNG;
+ }
+ else if (ext == "jpeg" || ext == "jpg")
+ {
+ format = LLSnapshotModel::SNAPSHOT_FORMAT_JPEG;
+ }
+ else if (ext != "bmp")
+ {
+ sendReply(llsd::map("error", stringize("Unrecognized format. [\"png\"], [\"jpeg\"] or [\"bmp\"] is expected.")), event);
+ return;
+ }
+ // take snapshot on the main coro
+ doOnIdleOneTime([this, event, filename, width, height, showui, showhud, rebuild, type, format]()
+ { sendReply(llsd::map("result", mViewerWindow->saveSnapshot(filename, width, height, showui, showhud, rebuild, type, format)), event); });
+
}
void LLViewerWindowListener::requestReshape(LLSD const & event_data) const
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index 077e6e6cb1..ca76d93cd7 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -320,7 +320,11 @@ LLViewerTexture* LLTerrainMaterials::getPaintMap()
void LLTerrainMaterials::setPaintMap(LLViewerTexture* paint_map)
{
llassert(!paint_map || mPaintType == TERRAIN_PAINT_TYPE_PBR_PAINTMAP);
+ const bool changed = paint_map != mPaintMap;
mPaintMap = paint_map;
+ // The paint map has changed, so edits are no longer valid
+ mPaintRequestQueue.clear();
+ mPaintMapQueue.clear();
}
// Boost the texture loading priority
diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h
index f15f9bff6a..21fd484375 100644
--- a/indra/newview/llvlcomposition.h
+++ b/indra/newview/llvlcomposition.h
@@ -31,6 +31,7 @@
#include "llviewershadermgr.h"
#include "llviewertexture.h"
#include "llpointer.h"
+#include "llterrainpaintmap.h"
#include "llimage.h"
@@ -87,6 +88,18 @@ public:
void setPaintType(U32 paint_type) { mPaintType = paint_type; }
LLViewerTexture* getPaintMap();
void setPaintMap(LLViewerTexture* paint_map);
+ // Queue of client-triggered brush operations that need to be converted
+ // into a form that can be sent to the server.
+ // TODO: Consider getting rid of mPaintRequestQueue, as it's not really needed (brushes go directly to RGB queue)
+ LLTerrainBrushQueue& getBrushQueue() { return mBrushQueue; }
+ // Queue of client-triggered paint operations that need to be converted
+ // into a form that can be sent to the server.
+ // Paints in this queue are in RGBA format.
+ LLTerrainPaintQueue& getPaintRequestQueue() { return mPaintRequestQueue; }
+ // Paint queue for current paint map - this queue gets applied directly to
+ // the paint map. Paints within are assumed to have already been sent to
+ // the server. Paints in this queue are in RGB format.
+ LLTerrainPaintQueue& getPaintMapQueue() { return mPaintMapQueue; }
protected:
void unboost();
@@ -105,6 +118,9 @@ protected:
U32 mPaintType = TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE;
LLPointer<LLViewerTexture> mPaintMap;
+ LLTerrainBrushQueue mBrushQueue;
+ LLTerrainPaintQueue mPaintRequestQueue{U8(4)};
+ LLTerrainPaintQueue mPaintMapQueue{U8(3)};
};
// Local materials to override all regions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 2ef45442ee..6b3caf2d0d 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -114,6 +114,7 @@
#include "llskinningutil.h"
#include "llperfstats.h"
+#include "lleventapi.h"
#include <boost/lexical_cast.hpp>
@@ -576,7 +577,7 @@ private:
// joint states to be animated
//-------------------------------------------------------------------------
LLPointer<LLJointState> mPelvisState;
- LLCharacter* mCharacter;
+ LLCharacter* mCharacter;
};
/**
@@ -684,6 +685,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mPreviousFullyLoaded(false),
mFullyLoadedInitialized(false),
mLastCloudAttachmentCount(0),
+ mFullyLoadedFrameCounter(0),
mVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mLoadedCallbacksPaused(false),
mLoadedCallbackTextures(0),
@@ -777,11 +779,9 @@ std::string LLVOAvatar::avString() const
{
return " " + getFullname() + " ";
}
- else
- {
- std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus());
- return " Avatar '" + getFullname() + "' " + viz_string + " ";
- }
+
+ std::string status = LLVOAvatar::rezStatusToString(getRezzedStatus());
+ return " Avatar '" + getDebugName() + "' " + status + " ";
}
void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment)
@@ -804,10 +804,10 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c
if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
{
LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
+ args["EXISTENCE"] = llformat("%d", (U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d", (U32)mRuthDebugTimer.getElapsedTimeF32());
args["NAME"] = getFullname();
- LLNotificationsUtil::add(notification_name,args);
+ LLNotificationsUtil::add(notification_name, args);
}
}
@@ -835,14 +835,14 @@ LLVOAvatar::~LLVOAvatar()
}
if (!mFullyLoaded)
{
- debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud");
+ debugAvatarRezTime("AvatarRezLeftCloudNotification", "left after ruth seconds as cloud");
}
else
{
- debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding");
+ debugAvatarRezTime("AvatarRezLeftNotification", "left sometime after declouding");
}
- if(mTuned)
+ if (mTuned)
{
LLPerfStats::tunedAvatars--;
mTuned = false;
@@ -984,7 +984,7 @@ bool LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars)
++grey_avatars;
}
}
- return !grey_avatars;
+ return grey_avatars == 0;
}
// static
@@ -1955,10 +1955,10 @@ bool LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
if (linesegment_sphere(LLVector3(glm::value_ptr(p1)), LLVector3(glm::value_ptr(p2)), LLVector3(0,0,0), 1.f, position, norm))
{
- glm::vec3 res_pos(glm::make_vec3(position.mV));
+ glm::vec3 res_pos(glm::make_vec3(LLVector4(position).mV));
res_pos = mul_mat4_vec3(mat, res_pos);
- glm::vec3 res_norm(glm::make_vec3(norm.mV));
+ glm::vec3 res_norm(glm::make_vec3(LLVector4(norm).mV));
res_norm = glm::normalize(res_norm);
res_norm = glm::mat3(norm_mat) * res_norm;
@@ -2869,11 +2869,11 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
S32 compl_upd_freq = 20;
if (isControlAvatar())
{
- // animeshes do not (or won't) have impostors nor change outfis,
+ // animeshes do not (or won't) have impostors nor change outfis,F
// no need for high frequency
compl_upd_freq = 100;
}
- else if (mLastRezzedStatus <= 0) //cloud or init
+ else if (mLastRezzedStatus <= 0) // cloud or initial
{
compl_upd_freq = 60;
}
@@ -2881,11 +2881,11 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
{
compl_upd_freq = 5;
}
- else if (mLastRezzedStatus == 1) //'grey', not fully loaded
+ else if (mLastRezzedStatus == 1) // 'gray', not fully loaded
{
compl_upd_freq = 40;
}
- else if (isInMuteList()) //cheap, buffers value from search
+ else if (isInMuteList()) // cheap, buffers value from search
{
compl_upd_freq = 100;
}
@@ -3007,7 +3007,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
if (LLVOAvatar::sJointDebug)
{
- LL_INFOS() << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL;
+ LL_INFOS() << getDebugName() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL;
}
LLJoint::sNumUpdates = 0;
@@ -3227,17 +3227,17 @@ F32 LLVOAvatar::calcMorphAmount() const
void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
{
// Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync
- if ( voice_enabled
+ if (voice_enabled
&& mLastRezzedStatus > 0 // no point updating lip-sync for clouds
&& LLVoiceVisualizer::getLipSyncEnabled()
- && LLVoiceClient::getInstance()->getIsSpeaking( mID ) )
+ && LLVoiceClient::getInstance()->getIsSpeaking(mID))
{
F32 ooh_morph_amount = 0.0f;
F32 aah_morph_amount = 0.0f;
mVoiceVisualizer->lipSyncOohAah( ooh_morph_amount, aah_morph_amount );
- if( mOohMorph )
+ if (mOohMorph)
{
F32 ooh_weight = mOohMorph->getMinWeight()
+ ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight());
@@ -3245,7 +3245,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
mOohMorph->setWeight( ooh_weight);
}
- if( mAahMorph )
+ if (mAahMorph)
{
F32 aah_weight = mAahMorph->getMinWeight()
+ aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight());
@@ -3809,6 +3809,7 @@ LLVector3 LLVOAvatar::idleCalcNameTagPosition(const LLVector3 &root_pos_last)
// Avoid of crossing the name tag by the water surface
if (mNameText)
{
+ bool hidden = false;
F32 water_height = getRegion()->getWaterHeight();
static const F32 WATER_HEIGHT_ABOVE_DELTA = 0.25;
if (name_position[VZ] < water_height + WATER_HEIGHT_ABOVE_DELTA)
@@ -3822,8 +3823,19 @@ LLVector3 LLVOAvatar::idleCalcNameTagPosition(const LLVector3 &root_pos_last)
{
name_position[VZ] = water_height + WATER_HEIGHT_ABOVE_DELTA;
}
+ else
+ {
+ // Hide the name tag when the camera is above the water
+ // but the avatar is deep enough under the water surface
+ hidden = true;
+ }
}
}
+
+ if (mNameText->getHidden() != hidden)
+ {
+ mNameText->setHidden(hidden);
+ }
}
return name_position;
@@ -6207,8 +6219,11 @@ void LLVOAvatar::resetAnimations()
flushAllMotions();
}
-// Override selectively based on avatar sex and whether we're using new
-// animations.
+//-----------------------------------------------------------------------------
+// remapMotionID()
+// Override selectively based on avatar sex and whether we're using new animations.
+//-----------------------------------------------------------------------------
+// virtual
LLUUID LLVOAvatar::remapMotionID(const LLUUID& id)
{
static LLCachedControl<bool> use_new_walk_run(gSavedSettings, "UseNewWalkRun");
@@ -6258,7 +6273,6 @@ LLUUID LLVOAvatar::remapMotionID(const LLUUID& id)
}
return result;
-
}
//-----------------------------------------------------------------------------
@@ -6327,6 +6341,7 @@ void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id)
//-----------------------------------------------------------------------------
// addDebugText()
//-----------------------------------------------------------------------------
+// virtual
void LLVOAvatar::addDebugText(const std::string& text)
{
mDebugText.append(1, '\n');
@@ -6334,8 +6349,22 @@ void LLVOAvatar::addDebugText(const std::string& text)
}
//-----------------------------------------------------------------------------
+// getDebugName()
+//-----------------------------------------------------------------------------
+// virtual
+std::string LLVOAvatar::getDebugName() const
+{
+#if LL_RELEASE_WITH_DEBUG_INFO
+ return getFullname();
+#else
+ return getID().asString();
+#endif // LL_RELEASE_WITH_DEBUG_INFO
+}
+
+//-----------------------------------------------------------------------------
// getID()
//-----------------------------------------------------------------------------
+// virtual
const LLUUID& LLVOAvatar::getID() const
{
return mID;
@@ -6345,6 +6374,7 @@ const LLUUID& LLVOAvatar::getID() const
// getJoint()
//-----------------------------------------------------------------------------
// RN: avatar joints are multi-rooted to include screen-based attachments
+// virtual
LLJoint *LLVOAvatar::getJoint( const std::string &name )
{
joint_map_t::iterator iter = mJointMap.find(name);
@@ -6613,11 +6643,11 @@ void LLVOAvatar::updateAttachmentOverrides()
}
}
pelvis_fixups = mPelvisFixups;
- //dumpArchetypeXML(getFullname() + "_paranoid_updated");
+ //dumpArchetypeXML(getDebugName() + "_paranoid_updated");
// Rebuild and compare
rebuildAttachmentOverrides();
- //dumpArchetypeXML(getFullname() + "_paranoid_rebuilt");
+ //dumpArchetypeXML(getDebugName() + "_paranoid_rebuilt");
bool mismatched = false;
for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++)
{
@@ -6846,22 +6876,22 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const
{
std::stringstream ss;
std::copy(pos_names.begin(), pos_names.end(), std::ostream_iterator<std::string>(ss, ","));
- LL_INFOS() << getFullname() << " attachment positions defined for joints: " << ss.str() << "\n" << LL_ENDL;
+ LL_INFOS() << avString() << " attachment positions defined for joints: " << ss.str() << "\n" << LL_ENDL;
}
else
{
- LL_DEBUGS("Avatar") << getFullname() << " no attachment positions defined for any joints" << "\n" << LL_ENDL;
+ LL_DEBUGS("Avatar") << avString() << " no attachment positions defined for any joints" << "\n" << LL_ENDL;
}
if (scale_names.size())
{
std::stringstream ss;
std::copy(scale_names.begin(), scale_names.end(), std::ostream_iterator<std::string>(ss, ","));
- LL_INFOS() << getFullname() << " attachment scales defined for joints: " << ss.str() << "\n" << LL_ENDL;
+ LL_INFOS() << getDebugName() << " attachment scales defined for joints: " << ss.str() << "\n" << LL_ENDL;
}
else
{
- LL_INFOS() << getFullname() << " no attachment scales defined for any joints" << "\n" << LL_ENDL;
+ LL_INFOS() << getDebugName() << " no attachment scales defined for any joints" << "\n" << LL_ENDL;
}
if (!verbose)
@@ -8232,7 +8262,7 @@ bool LLVOAvatar::getIsCloud() const
void LLVOAvatar::updateRezzedStatusTimers(S32 rez_status)
{
// State machine for rezzed status. Statuses are -1 on startup, 0
- // = cloud, 1 = gray, 2 = downloading, 3 = waiting for attachments, 4 = full.
+ // Statuses are -1 on startup, 0 = cloud, 1 = gray, 2 = downloading, 3 = waiting for attachments, 4 = full.
// Purpose is to collect time data for each it takes avatar to reach
// various loading landmarks: gray, textured (partial), textured fully.
@@ -8496,19 +8526,19 @@ bool LLVOAvatar::processFullyLoadedChange(bool loading)
F32 first_use_delay = FIRST_APPEARANCE_CLOUD_MIN_DELAY;
if (!isSelf() && loading)
{
- // Note that textures can causes 60s delay on thier own
- // so this delay might end up on top of textures' delay
- first_use_delay = llclamp(
- mFirstAppearanceMessageTimer.getElapsedTimeF32(),
- FIRST_APPEARANCE_CLOUD_MIN_DELAY,
- FIRST_APPEARANCE_CLOUD_MAX_DELAY);
+ // Note that textures can causes 60s delay on thier own
+ // so this delay might end up on top of textures' delay
+ first_use_delay = llclamp(
+ mFirstAppearanceMessageTimer.getElapsedTimeF32(),
+ FIRST_APPEARANCE_CLOUD_MIN_DELAY,
+ FIRST_APPEARANCE_CLOUD_MAX_DELAY);
- if (shouldImpostor())
- {
- // Impostors are less of a priority,
- // let them stay cloud longer
- first_use_delay *= FIRST_APPEARANCE_CLOUD_IMPOSTOR_MODIFIER;
- }
+ if (shouldImpostor())
+ {
+ // Impostors are less of a priority,
+ // let them stay cloud longer
+ first_use_delay *= FIRST_APPEARANCE_CLOUD_IMPOSTOR_MODIFIER;
+ }
}
mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > first_use_delay);
}
@@ -8528,8 +8558,8 @@ bool LLVOAvatar::processFullyLoadedChange(bool loading)
const S32 UPDATE_RATE = 30;
bool changed =
((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call
- (!mFullyLoadedInitialized) || // if we've never been called before
- (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change
+ (!mFullyLoadedInitialized) || // if we've never been called before
+ (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change
bool fully_loaded_changed = (mFullyLoaded != mPreviousFullyLoaded);
mPreviousFullyLoaded = mFullyLoaded;
@@ -9436,12 +9466,12 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)
void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
const LLAppearanceMessageContents& contents)
{
- std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");
+ std::string outfilename = get_sequential_numbered_file_name(dump_prefix, ".xml");
const std::vector<F32>& params_for_dump = contents.mParamWeights;
const LLTEContents& tec = contents.mTEContents;
LLAPRFile outfile;
- std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
+ std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, outfilename);
outfile.open(fullpath, LL_APR_WB );
apr_file_t* file = outfile.getFileHandle();
if (!file)
@@ -9654,7 +9684,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
static LLCachedControl<bool> enable_verbose_dumps(gSavedSettings, "DebugAvatarAppearanceMessage");
static LLCachedControl<bool> block_avatar_appearance_messages(gSavedSettings, "BlockAvatarAppearanceMessages");
- std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_";
+ std::string dump_prefix = getDebugName() + (isSelf() ? "_s_" : "_o_");
if (block_avatar_appearance_messages)
{
LL_WARNS() << "Blocking AvatarAppearance message" << LL_ENDL;
@@ -10288,7 +10318,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
std::string outprefix(prefix);
if (outprefix.empty())
{
- outprefix = getFullname() + (isSelf()?"_s":"_o");
+ outprefix = getDebugName() + (isSelf()?"_s":"_o");
}
if (outprefix.empty())
{
@@ -10784,7 +10814,7 @@ void LLVOAvatar::updateRiggingInfo()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL;
+ LL_DEBUGS("RigSpammish") << getDebugName() << " updating rig tab" << LL_ENDL;
// use a local static for scratch space to avoid reallocation here
static std::vector<LLVOVolume*> volumes;
@@ -10828,7 +10858,7 @@ void LLVOAvatar::updateRiggingInfo()
//LL_INFOS() << "done update rig count is " << countRigInfoTab(mJointRiggingInfoTab) << LL_ENDL;
// Remove debug only stuff on hot path
- // LL_DEBUGS("RigSpammish") << getFullname() << " after update rig tab:" << LL_ENDL;
+ // LL_DEBUGS("RigSpammish") << getDebugName() << " after update rig tab:" << LL_ENDL;
// S32 joint_count, box_count;
// showRigInfoTabExtents(this, mJointRiggingInfoTab, joint_count, box_count);
// LL_DEBUGS("RigSpammish") << "uses " << joint_count << " joints " << " nonzero boxes: " << box_count << LL_ENDL;
@@ -11874,3 +11904,33 @@ bool LLVOAvatar::isBuddy() const
return is_friend;
}
+class LLVOAvatarListener : public LLEventAPI
+{
+ public:
+ LLVOAvatarListener() : LLEventAPI("LLVOAvatar", "LLVOAvatar listener to retrieve avatar info")
+ {
+ add("getSpeed",
+ "Return the avatar movement speed in the XY plane",
+ &LLVOAvatarListener::getSpeed,
+ LLSD().with("reply", LLSD()));
+ add("isInAir",
+ "Return the info whether avatar is in the air, and if so the time in the air",
+ &LLVOAvatarListener::isInAir,
+ LLSD().with("reply", LLSD()));
+ }
+
+ private:
+ void getSpeed(const LLSD &request) const
+ {
+ LLVector3 avatar_velocity = gAgentAvatarp->getCharacterVelocity() * gAgentAvatarp->getTimeDilation();
+ avatar_velocity.mV[VZ] = 0.f;
+ Response response(llsd::map("value", avatar_velocity.magVec()), request);
+ }
+ void isInAir(const LLSD &request) const
+ {
+ Response response(llsd::map("value", gAgentAvatarp->mInAir,
+ "duration", gAgentAvatarp->mInAir ? gAgentAvatarp->mTimeInAir.getElapsedTimeF32() : 0), request);
+ }
+};
+
+static LLVOAvatarListener VOAvatarListener;
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index dd1725c322..d377ebad41 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -231,7 +231,8 @@ public:
std::set<LLUUID> mActiveOverrideMeshes;
virtual void onActiveOverrideMeshesChanged();
- /*virtual*/ const LLUUID& getID() const;
+/*virtual*/ const LLUUID& getID() const;
+ /*virtual*/ std::string getDebugName() const;
/*virtual*/ void addDebugText(const std::string& text);
/*virtual*/ F32 getTimeDilation();
/*virtual*/ void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm);
@@ -329,16 +330,16 @@ public:
// avatar render cost
- U32 getVisualComplexity() { return mVisualComplexity; };
+ U32 getVisualComplexity() { return mVisualComplexity; };
// surface area calculation
- F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; };
+ F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; };
- U32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server
- void setReportedVisualComplexity(U32 value) { mReportedVisualComplexity = value; };
+ U32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server
+ void setReportedVisualComplexity(U32 value) { mReportedVisualComplexity = value; };
- S32 getUpdatePeriod() { return mUpdatePeriod; };
- const LLColor4 & getMutedAVColor() { return mMutedAVColor; };
+ S32 getUpdatePeriod() { return mUpdatePeriod; };
+ const LLColor4 & getMutedAVColor() { return mMutedAVColor; };
static void updateImpostorRendering(U32 newMaxNonImpostorsValue);
void idleUpdateBelowWater();
@@ -401,7 +402,7 @@ public:
virtual bool getIsCloud() const;
bool isFullyTextured() const;
bool hasGray() const;
- S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = textured, 3 = textured and fully downloaded.
+ S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = textured, 3 = waiting for attachments, 4 = full.
void updateRezzedStatusTimers(S32 status);
S32 mLastRezzedStatus;
@@ -740,7 +741,7 @@ protected:
LLViewerTexLayerSet* getTexLayerSet(const U32 index) const { return dynamic_cast<LLViewerTexLayerSet*>(mBakedTextureDatas[index].mTexLayerSet); }
- LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ;
+ LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList;
bool mLoadedCallbacksPaused;
S32 mLoadedCallbackTextures; // count of 'loaded' baked textures, filled from mCallbackTextureList
LLFrameTimer mLastTexCallbackAddedTime;
diff --git a/indra/newview/llvoicecallhandler.cpp b/indra/newview/llvoicecallhandler.cpp
index 25b0e69436..d2c947fef2 100644
--- a/indra/newview/llvoicecallhandler.cpp
+++ b/indra/newview/llvoicecallhandler.cpp
@@ -38,6 +38,11 @@ public:
{
}
+ virtual bool canHandleUntrusted(const LLSD &params, const LLSD &query_map, LLMediaCtrl *web, const std::string &nav_type)
+ {
+ return (nav_type == NAV_TYPE_CLICKED || nav_type == NAV_TYPE_EXTERNAL);
+ }
+
bool handle(const LLSD& params, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
{
//Make sure we have some parameters
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index 55769f567b..b60337ee14 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -370,6 +370,12 @@ void LLVoiceChannel::resume()
{
if (sSuspendedVoiceChannel)
{
+ if (sSuspendedVoiceChannel->callStarted())
+ {
+ // should have channel data already, restart
+ sSuspendedVoiceChannel->setState(STATE_READY);
+ }
+ // won't do anything if call is already started
sSuspendedVoiceChannel->activate();
}
else
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 846c2b8867..0e11854019 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -439,6 +439,16 @@ void LLVoiceClient::setRenderDevice(const std::string& name)
#endif
}
+bool LLVoiceClient::isCaptureNoDevice()
+{
+ return LLWebRTCVoiceClient::getInstance()->isCaptureNoDevice();
+}
+
+bool LLVoiceClient::isRenderNoDevice()
+{
+ return LLWebRTCVoiceClient::getInstance()->isRenderNoDevice();
+}
+
const LLVoiceDeviceList& LLVoiceClient::getCaptureDevices()
{
#if !__FreeBSD__
@@ -448,7 +458,6 @@ const LLVoiceDeviceList& LLVoiceClient::getCaptureDevices()
#endif
}
-
const LLVoiceDeviceList& LLVoiceClient::getRenderDevices()
{
#if !__FreeBSD__
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index d53f512d82..2731b0cc7f 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -192,6 +192,9 @@ public:
virtual LLVoiceDeviceList& getCaptureDevices()=0;
virtual LLVoiceDeviceList& getRenderDevices()=0;
+ virtual bool isCaptureNoDevice() = 0;
+ virtual bool isRenderNoDevice() = 0;
+
virtual void getParticipantList(std::set<LLUUID> &participants)=0;
virtual bool isParticipant(const LLUUID& speaker_id)=0;
//@}
@@ -392,6 +395,8 @@ public:
void setCaptureDevice(const std::string& name);
void setRenderDevice(const std::string& name);
+ bool isCaptureNoDevice();
+ bool isRenderNoDevice();
void setHidden(bool hidden);
const LLVoiceDeviceList& getCaptureDevices();
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 6bd06e6474..8a6cf948f9 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -2784,6 +2784,7 @@ void LLVivoxVoiceClient::setCaptureDevice(const std::string& name)
}
}
}
+
void LLVivoxVoiceClient::setDevicesListUpdated(bool state)
{
mDevicesListUpdated = state;
@@ -6646,13 +6647,13 @@ void LLVivoxVoiceClient::expireVoiceFonts()
}
}
- LLSD args;
- args["URL"] = LLTrans::getString("voice_morphing_url");
- args["PREMIUM_URL"] = LLTrans::getString("premium_voice_morphing_url");
-
// Give a notification if any voice fonts have expired.
if (have_expired)
{
+ LLSD args;
+ args["URL"] = LLTrans::getString("voice_morphing_url");
+ args["PREMIUM_URL"] = LLTrans::getString("premium_voice_morphing_url");
+
if (expired_in_use)
{
LLNotificationsUtil::add("VoiceEffectsExpiredInUse", args);
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 3e0a237905..6befadb5ff 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -123,6 +123,9 @@ public:
void setCaptureDevice(const std::string& name) override;
void setRenderDevice(const std::string& name) override;
+ bool isCaptureNoDevice() override { return false; };
+ bool isRenderNoDevice() override { return false; };
+
LLVoiceDeviceList& getCaptureDevices() override;
LLVoiceDeviceList& getRenderDevices() override;
//@}
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index ad8f6927ed..6d4f3fe356 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -203,6 +203,7 @@ LLWebRTCVoiceClient::LLWebRTCVoiceClient() :
mTuningMode(false),
mTuningMicGain(0.0),
mTuningSpeakerVolume(50), // Set to 50 so the user can hear themselves when he sets his mic volume
+ mDeviceSettingsAvailable(false),
mDevicesListUpdated(false),
mSpatialCoordsDirty(false),
@@ -218,7 +219,7 @@ LLWebRTCVoiceClient::LLWebRTCVoiceClient() :
mAvatarNameCacheConnection(),
mIsInTuningMode(false),
mIsProcessingChannels(false),
- mIsCoroutineActive(false),
+ mIsTimerActive(false),
mWebRTCPump("WebRTCClientPump"),
mWebRTCDeviceInterface(nullptr)
{
@@ -295,6 +296,20 @@ void LLWebRTCVoiceClient::cleanUp()
mNeighboringRegions.clear();
sessionState::for_each(boost::bind(predShutdownSession, _1));
LL_DEBUGS("Voice") << "Exiting" << LL_ENDL;
+ stopTimer();
+}
+
+void LLWebRTCVoiceClient::stopTimer()
+{
+ if (mIsTimerActive)
+ {
+ LLMuteList::instanceExists();
+ {
+ LLMuteList::getInstance()->removeObserver(this);
+ }
+ mIsTimerActive = false;
+ LL::Timers::instance().cancel(mVoiceTimerHandle);
+ }
}
void LLWebRTCVoiceClient::LogMessage(llwebrtc::LLWebRTCLogCallback::LogLevel level, const std::string& message)
@@ -443,8 +458,7 @@ void LLWebRTCVoiceClient::removeObserver(LLFriendObserver *observer)
//---------------------------------------------------
// Primary voice loop.
-// This voice loop is called every 100ms plus the time it
-// takes to process the various functions called in the loop
+// This voice loop is called every 100ms
// The loop does the following:
// * gates whether we do channel processing depending on
// whether we're running a WebRTC voice channel or
@@ -456,102 +470,94 @@ void LLWebRTCVoiceClient::removeObserver(LLFriendObserver *observer)
// connection to various voice channels.
// * Sends updates to the voice server when this agent's
// voice levels, or positions have changed.
-void LLWebRTCVoiceClient::voiceConnectionCoro()
+void LLWebRTCVoiceClient::connectionTimer()
{
- LL_DEBUGS("Voice") << "starting" << LL_ENDL;
- mIsCoroutineActive = true;
- LLCoros::set_consuming(true);
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE;
try
{
- LLMuteList::getInstance()->addObserver(this);
- while (!sShuttingDown)
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE("voiceConnectionCoroLoop")
- // TODO: Doing some measurement and calculation here,
- // we could reduce the timeout to take into account the
- // time spent on the previous loop to have the loop
- // cycle at exactly 100ms, instead of 100ms + loop
- // execution time.
- // Could help with voice updates making for smoother
- // voice when we're busy.
- llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
- if (sShuttingDown) return; // 'this' migh already be invalid
- bool voiceEnabled = mVoiceEnabled;
-
- if (!isAgentAvatarValid())
+ bool voiceEnabled = mVoiceEnabled;
+
+ if (!isAgentAvatarValid())
+ {
+ if (sShuttingDown)
{
- continue;
+ cleanUp();
}
+ return;
+ }
- LLViewerRegion *regionp = gAgent.getRegion();
- if (!regionp)
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (!regionp)
+ {
+ if (sShuttingDown)
{
- continue;
+ cleanUp();
}
+ return;
+ }
- if (!mProcessChannels)
+ if (!mProcessChannels)
+ {
+ // we've switched away from webrtc voice, so shut all channels down.
+ // leave channel can be called again and again without adverse effects.
+ // it merely tells channels to shut down if they're not already doing so.
+ leaveChannel(false);
+ }
+ else if (inSpatialChannel())
+ {
+ bool useEstateVoice = true;
+ // add session for region or parcel voice.
+ if (!regionp || regionp->getRegionID().isNull())
{
- // we've switched away from webrtc voice, so shut all channels down.
- // leave channel can be called again and again without adverse effects.
- // it merely tells channels to shut down if they're not already doing so.
- leaveChannel(false);
+ // no region, no voice.
+ return;
}
- else if (inSpatialChannel())
- {
- bool useEstateVoice = true;
- // add session for region or parcel voice.
- if (!regionp || regionp->getRegionID().isNull())
- {
- // no region, no voice.
- continue;
- }
- voiceEnabled = voiceEnabled && regionp->isVoiceEnabled();
+ voiceEnabled = voiceEnabled && regionp->isVoiceEnabled();
- if (voiceEnabled)
+ if (voiceEnabled)
+ {
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ // check to see if parcel changed.
+ if (parcel && parcel->getLocalID() != INVALID_PARCEL_ID)
{
- LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- // check to see if parcel changed.
- if (parcel && parcel->getLocalID() != INVALID_PARCEL_ID)
+ // parcel voice
+ if (!parcel->getParcelFlagAllowVoice())
{
- // parcel voice
- if (!parcel->getParcelFlagAllowVoice())
- {
- voiceEnabled = false;
- }
- else if (!parcel->getParcelFlagUseEstateVoiceChannel())
- {
- // use the parcel-specific voice channel.
- S32 parcel_local_id = parcel->getLocalID();
- std::string channelID = regionp->getRegionID().asString() + "-" + std::to_string(parcel->getLocalID());
-
- useEstateVoice = false;
- if (!inOrJoiningChannel(channelID))
- {
- startParcelSession(channelID, parcel_local_id);
- }
- }
+ voiceEnabled = false;
}
- if (voiceEnabled && useEstateVoice && !inEstateChannel())
+ else if (!parcel->getParcelFlagUseEstateVoiceChannel())
{
- // estate voice
- startEstateSession();
+ // use the parcel-specific voice channel.
+ S32 parcel_local_id = parcel->getLocalID();
+ std::string channelID = regionp->getRegionID().asString() + "-" + std::to_string(parcel->getLocalID());
+
+ useEstateVoice = false;
+ if (!inOrJoiningChannel(channelID))
+ {
+ startParcelSession(channelID, parcel_local_id);
+ }
}
}
- if (!voiceEnabled)
+ if (voiceEnabled && useEstateVoice && !inEstateChannel())
{
- // voice is disabled, so leave and disable PTT
- leaveChannel(true);
- }
- else
- {
- // we're in spatial voice, and voice is enabled, so determine positions in order
- // to send position updates.
- updatePosition();
+ // estate voice
+ startEstateSession();
}
}
+ if (!voiceEnabled)
+ {
+ // voice is disabled, so leave and disable PTT
+ leaveChannel(true);
+ }
+ else
+ {
+ // we're in spatial voice, and voice is enabled, so determine positions in order
+ // to send position updates.
+ updatePosition();
+ }
LL::WorkQueue::postMaybe(mMainQueue,
- [=] {
+ [=, this] {
if (sShuttingDown)
{
return;
@@ -565,10 +571,6 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
});
}
}
- catch (const LLCoros::Stop&)
- {
- LL_DEBUGS("LLWebRTCVoiceClient") << "Received a shutdown exception" << LL_ENDL;
- }
catch (const LLContinueError&)
{
LOG_UNHANDLED_EXCEPTION("LLWebRTCVoiceClient");
@@ -582,7 +584,10 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
throw;
}
- cleanUp();
+ if (sShuttingDown)
+ {
+ cleanUp();
+ }
}
// For spatial, determine which neighboring regions to connect to
@@ -640,12 +645,14 @@ void LLWebRTCVoiceClient::leaveAudioSession()
void LLWebRTCVoiceClient::clearCaptureDevices()
{
LL_DEBUGS("Voice") << "called" << LL_ENDL;
+ mDeviceSettingsAvailable = false;
mCaptureDevices.clear();
}
void LLWebRTCVoiceClient::addCaptureDevice(const LLVoiceDevice& device)
{
LL_INFOS("Voice") << "Voice Capture Device: '" << device.display_name << "' (" << device.full_name << ")" << LL_ENDL;
+ mDeviceSettingsAvailable = false;
mCaptureDevices.push_back(device);
}
@@ -658,6 +665,7 @@ void LLWebRTCVoiceClient::setCaptureDevice(const std::string& name)
{
mWebRTCDeviceInterface->setCaptureDevice(name);
}
+
void LLWebRTCVoiceClient::setDevicesListUpdated(bool state)
{
mDevicesListUpdated = state;
@@ -669,7 +677,7 @@ void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceLi
{
LL::WorkQueue::postMaybe(mMainQueue,
- [=]
+ [=, this]
{
OnDevicesChangedImpl(render_devices, capture_devices);
});
@@ -703,20 +711,22 @@ void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDevi
}
setCaptureDevice(inputDevice);
+ mDeviceSettingsAvailable = true;
setDevicesListUpdated(true);
}
void LLWebRTCVoiceClient::clearRenderDevices()
{
LL_DEBUGS("Voice") << "called" << LL_ENDL;
+ mDeviceSettingsAvailable = false;
mRenderDevices.clear();
}
void LLWebRTCVoiceClient::addRenderDevice(const LLVoiceDevice& device)
{
LL_INFOS("Voice") << "Voice Render Device: '" << device.display_name << "' (" << device.full_name << ")" << LL_ENDL;
+ mDeviceSettingsAvailable = false;
mRenderDevices.push_back(device);
-
}
LLVoiceDeviceList& LLWebRTCVoiceClient::getRenderDevices()
@@ -729,6 +739,16 @@ void LLWebRTCVoiceClient::setRenderDevice(const std::string& name)
mWebRTCDeviceInterface->setRenderDevice(name);
}
+bool LLWebRTCVoiceClient::isCaptureNoDevice()
+{
+ return mCaptureDevices.empty() || mWebRTCDeviceInterface->isCaptureNoDevice();
+}
+
+bool LLWebRTCVoiceClient::isRenderNoDevice()
+{
+ return mRenderDevices.empty() || mWebRTCDeviceInterface->isRenderNoDevice();
+}
+
void LLWebRTCVoiceClient::tuningStart()
{
if (!mIsInTuningMode)
@@ -754,11 +774,15 @@ bool LLWebRTCVoiceClient::inTuningMode()
void LLWebRTCVoiceClient::tuningSetMicVolume(float volume)
{
- mTuningMicGain = volume;
+ mTuningMicGain = volume;
}
void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume)
{
+ if (isRenderNoDevice())
+ {
+ volume = 0;
+ }
if (volume != mTuningSpeakerVolume)
{
@@ -768,14 +792,17 @@ void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume)
float LLWebRTCVoiceClient::getAudioLevel()
{
- if (mIsInTuningMode)
+ if (isCaptureNoDevice())
{
- return (1.0f - mWebRTCDeviceInterface->getTuningAudioLevel() * LEVEL_SCALE_WEBRTC) * mTuningMicGain / 2.1f;
+ return 0;
}
- else
+
+ if (mIsInTuningMode)
{
- return (1.0f - mWebRTCDeviceInterface->getPeerConnectionAudioLevel() * LEVEL_SCALE_WEBRTC) * mMicGain / 2.1f;
+ return (1.0f - mWebRTCDeviceInterface->getTuningAudioLevel() * LEVEL_SCALE_WEBRTC) * mTuningMicGain / 2.1f;
}
+
+ return (1.0f - mWebRTCDeviceInterface->getPeerConnectionAudioLevel() * LEVEL_SCALE_WEBRTC) * mMicGain / 2.1f;
}
float LLWebRTCVoiceClient::tuningGetEnergy(void)
@@ -783,15 +810,6 @@ float LLWebRTCVoiceClient::tuningGetEnergy(void)
return getAudioLevel();
}
-bool LLWebRTCVoiceClient::deviceSettingsAvailable()
-{
- bool result = true;
-
- if(mRenderDevices.empty() || mCaptureDevices.empty())
- result = false;
-
- return result;
-}
bool LLWebRTCVoiceClient::deviceSettingsUpdated()
{
bool updated = mDevicesListUpdated;
@@ -801,7 +819,7 @@ bool LLWebRTCVoiceClient::deviceSettingsUpdated()
void LLWebRTCVoiceClient::refreshDeviceLists(bool clearCurrentList)
{
- if(clearCurrentList)
+ if (clearCurrentList)
{
clearCaptureDevices();
clearRenderDevices();
@@ -809,7 +827,6 @@ void LLWebRTCVoiceClient::refreshDeviceLists(bool clearCurrentList)
mWebRTCDeviceInterface->refreshDevices();
}
-
void LLWebRTCVoiceClient::setHidden(bool hidden)
{
mHidden = hidden;
@@ -1340,7 +1357,7 @@ bool LLWebRTCVoiceClient::isVoiceWorking() const
// webrtc is working if the coroutine is active in the case of
// webrtc. WebRTC doesn't need to connect to a secondary process
// or a login server to become active.
- return mIsCoroutineActive;
+ return mIsTimerActive;
}
// Returns true if calling back the session URI after the session has closed is possible.
@@ -1523,9 +1540,7 @@ void LLWebRTCVoiceClient::setVoiceVolume(F32 volume)
{
if (volume != mSpeakerVolume)
{
- {
- mSpeakerVolume = volume;
- }
+ mSpeakerVolume = volume;
sessionState::for_each(boost::bind(predSetSpeakerVolume, _1, volume));
}
}
@@ -1544,7 +1559,6 @@ void LLWebRTCVoiceClient::setMicGain(F32 gain)
}
}
-
void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE;
@@ -1552,7 +1566,7 @@ void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled)
LL_DEBUGS("Voice")
<< "( " << (enabled ? "enabled" : "disabled") << " )"
<< " was "<< (mVoiceEnabled ? "enabled" : "disabled")
- << " coro "<< (mIsCoroutineActive ? "active" : "inactive")
+ << " coro "<< (mIsTimerActive ? "active" : "inactive")
<< LL_ENDL;
if (enabled != mVoiceEnabled)
@@ -1569,10 +1583,12 @@ void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled)
status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED;
mSpatialCoordsDirty = true;
updatePosition();
- if (!mIsCoroutineActive)
+ if (!mIsTimerActive)
{
- LLCoros::instance().launch("LLWebRTCVoiceClient::voiceConnectionCoro",
- boost::bind(&LLWebRTCVoiceClient::voiceConnectionCoro, LLWebRTCVoiceClient::getInstance()));
+ LL_DEBUGS("Voice") << "Starting" << LL_ENDL;
+ mIsTimerActive = true;
+ LLMuteList::getInstance()->addObserver(this);
+ mVoiceTimerHandle = LL::Timers::instance().scheduleEvery([this]() { connectionTimer(); return false; }, UPDATE_THROTTLE_SECONDS);
}
else
{
@@ -2172,7 +2188,7 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID &regionID, const s
// retries wait a short period...randomize it so
// all clients don't try to reconnect at once.
- mRetryWaitSecs = (F32)((F32) rand() / (RAND_MAX)) + 0.5f;
+ mRetryWaitSecs = static_cast<F32>(rand()) / static_cast<F32>(RAND_MAX) + 0.5f;
mWebRTCPeerConnectionInterface = llwebrtc::newPeerConnection();
mWebRTCPeerConnectionInterface->setSignalingObserver(this);
@@ -2205,7 +2221,7 @@ LLVoiceWebRTCConnection::~LLVoiceWebRTCConnection()
void LLVoiceWebRTCConnection::OnIceGatheringState(llwebrtc::LLWebRTCSignalingObserver::EIceGatheringState state)
{
LL::WorkQueue::postMaybe(mMainQueue,
- [=] {
+ [=, this] {
LL_DEBUGS("Voice") << "Ice Gathering voice account. " << state << LL_ENDL;
switch (state)
@@ -2228,7 +2244,7 @@ void LLVoiceWebRTCConnection::OnIceGatheringState(llwebrtc::LLWebRTCSignalingObs
// callback from llwebrtc
void LLVoiceWebRTCConnection::OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate& candidate)
{
- LL::WorkQueue::postMaybe(mMainQueue, [=] { mIceCandidates.push_back(candidate); });
+ LL::WorkQueue::postMaybe(mMainQueue, [=, this] { mIceCandidates.push_back(candidate); });
}
void LLVoiceWebRTCConnection::processIceUpdates()
@@ -2346,7 +2362,7 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection)
void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
{
LL::WorkQueue::postMaybe(mMainQueue,
- [=] {
+ [=, this] {
if (mShutDown)
{
return;
@@ -2373,7 +2389,7 @@ void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface* audio_interface)
{
LL::WorkQueue::postMaybe(mMainQueue,
- [=] {
+ [=, this] {
if (mShutDown)
{
return;
@@ -2395,7 +2411,7 @@ void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterfac
void LLVoiceWebRTCConnection::OnRenegotiationNeeded()
{
LL::WorkQueue::postMaybe(mMainQueue,
- [=] {
+ [=, this] {
LL_DEBUGS("Voice") << "Voice channel requires renegotiation." << LL_ENDL;
if (!mShutDown)
{
@@ -2409,7 +2425,7 @@ void LLVoiceWebRTCConnection::OnRenegotiationNeeded()
void LLVoiceWebRTCConnection::OnPeerConnectionClosed()
{
LL::WorkQueue::postMaybe(mMainQueue,
- [=] {
+ [=, this] {
LL_DEBUGS("Voice") << "Peer connection has closed." << LL_ENDL;
if (mVoiceConnectionState == VOICE_STATE_WAIT_FOR_CLOSE)
{
@@ -2768,7 +2784,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
case VOICE_STATE_SESSION_UP:
{
mRetryWaitPeriod = 0;
- mRetryWaitSecs = (F32)((F32)rand() / (RAND_MAX)) + 0.5f;
+ mRetryWaitSecs = (F32)((F32)rand() / (F32)RAND_MAX) + 0.5f;
// we'll stay here as long as the session remains up.
if (mShutDown)
@@ -2802,7 +2818,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
{
// back off the retry period, and do it by a small random
// bit so all clients don't reconnect at once.
- mRetryWaitSecs += (F32)((F32) rand() / (RAND_MAX)) + 0.5f;
+ mRetryWaitSecs += static_cast<F32>(rand()) / static_cast<F32>(RAND_MAX) + 0.5f;
mRetryWaitPeriod = 0;
}
}
@@ -2881,7 +2897,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
// llwebrtc callback
void LLVoiceWebRTCConnection::OnDataReceived(const std::string& data, bool binary)
{
- LL::WorkQueue::postMaybe(mMainQueue, [=] { LLVoiceWebRTCConnection::OnDataReceivedImpl(data, binary); });
+ LL::WorkQueue::postMaybe(mMainQueue, [=, this] { LLVoiceWebRTCConnection::OnDataReceivedImpl(data, binary); });
}
//
@@ -3037,7 +3053,7 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b
void LLVoiceWebRTCConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface)
{
LL::WorkQueue::postMaybe(mMainQueue,
- [=] {
+ [=, this] {
if (mShutDown)
{
return;
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h
index ff82d2739d..88ead98950 100644
--- a/indra/newview/llvoicewebrtc.h
+++ b/indra/newview/llvoicewebrtc.h
@@ -30,6 +30,7 @@ class LLWebRTCProtocolParser;
#include "lliopipe.h"
#include "llpumpio.h"
+#include "llcallbacklist.h"
#include "llchainio.h"
#include "lliosocket.h"
#include "v3math.h"
@@ -113,7 +114,7 @@ public:
/// @name Devices
//@{
// This returns true when it's safe to bring up the "device settings" dialog in the prefs.
- bool deviceSettingsAvailable() override;
+ bool deviceSettingsAvailable() override { return mDeviceSettingsAvailable; }
bool deviceSettingsUpdated() override; //return if the list has been updated and never fetched, only to be called from the voicepanel.
// Requery the WebRTC daemon for the current list of input/output devices.
@@ -125,6 +126,9 @@ public:
void setCaptureDevice(const std::string& name) override;
void setRenderDevice(const std::string& name) override;
+ bool isCaptureNoDevice() override;
+ bool isRenderNoDevice() override;
+
LLVoiceDeviceList& getCaptureDevices() override;
LLVoiceDeviceList& getRenderDevices() override;
//@}
@@ -447,19 +451,23 @@ private:
// Coroutine support methods
//---
- void voiceConnectionCoro();
+ void connectionTimer();
//---
/// Clean up objects created during a voice session.
void cleanUp();
+ // stop state machine
+ void stopTimer();
+
LL::WorkQueue::weak_t mMainQueue;
bool mTuningMode;
F32 mTuningMicGain;
int mTuningSpeakerVolume;
+ bool mDeviceSettingsAvailable;
bool mDevicesListUpdated; // set to true when the device list has been updated
- // and false when the panelvoicedevicesettings has queried for an update status.
+ // and false when the panelvoicedevicesettings has queried for an update status.
std::string mSpatialSessionCredentials;
std::string mMainSessionGroupHandle; // handle of the "main" session group.
@@ -534,7 +542,8 @@ private:
bool mIsInTuningMode;
bool mIsProcessingChannels;
- bool mIsCoroutineActive;
+ bool mIsTimerActive;
+ LL::Timers::handle_t mVoiceTimerHandle;
// These variables can last longer than WebRTC in coroutines so we need them as static
static bool sShuttingDown;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 149b60ca53..43bb1c177c 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -250,10 +250,12 @@ LLVOVolume::~LLVOVolume()
delete mVolumeImpl;
mVolumeImpl = NULL;
- gMeshRepo.unregisterMesh(this);
+ unregisterOldMeshAndSkin();
if(!mMediaImplList.empty())
{
+ LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("delete volume media list");
+
for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
{
if(mMediaImplList[i].notNull())
@@ -998,6 +1000,28 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
return mDrawable;
}
+// Inverse of gMeshRepo.loadMesh and gMeshRepo.getSkinInfo, combined into one function
+// Assume a Collada mesh never changes after being set.
+void LLVOVolume::unregisterOldMeshAndSkin()
+{
+ if (mVolumep)
+ {
+ const LLVolumeParams& params = mVolumep->getParams();
+ if ((params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ {
+ // object is being deleted, so it will no longer need to request
+ // meshes.
+ for (S32 lod = 0; lod != LLVolumeLODGroup::NUM_LODS; ++lod)
+ {
+ gMeshRepo.unregisterMesh(this, params, lod);
+ }
+ // This volume may or may not have a skin
+ gMeshRepo.unregisterSkinInfo(params.getSculptID(), this);
+ }
+ }
+}
+
+
bool LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
@@ -1511,11 +1535,16 @@ bool LLVOVolume::calcLOD()
mLODAdjustedDistance = distance;
+ static LLCachedControl<S32> debug_selection_lods(gSavedSettings, "DebugSelectionLODs", 0);
if (isHUDAttachment())
{
// HUDs always show at highest detail
cur_detail = 3;
}
+ else if (isSelected() && debug_selection_lods() >= 0)
+ {
+ cur_detail = llmin(debug_selection_lods(), 3);
+ }
else
{
cur_detail = computeLODDetail(ll_round(distance, 0.01f), ll_round(radius, 0.01f), lod_factor);
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 97a5131260..10dbf1349f 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -227,6 +227,7 @@ public:
void setTexture(const S32 face);
S32 getIndexInTex(U32 ch) const {return mIndexInTex[ch];}
+ void unregisterOldMeshAndSkin();
/*virtual*/ bool setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false) override;
void updateSculptTexture();
void setIndexInTex(U32 ch, S32 index) { mIndexInTex[ch] = index ;}
diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp
index 0a1d346266..d9fcd5811d 100644
--- a/indra/newview/llwatchdog.cpp
+++ b/indra/newview/llwatchdog.cpp
@@ -27,9 +27,10 @@
#include "llviewerprecompiledheaders.h"
#include "llwatchdog.h"
+#include "llmutex.h"
#include "llthread.h"
-const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000;
+constexpr U32 WATCHDOG_SLEEP_TIME_USEC = 1000000U;
// This class runs the watchdog timing thread.
class LLWatchdogTimerThread : public LLThread
@@ -51,7 +52,7 @@ public:
mSleepMsecs = 1;
}
- /* virtual */ void run()
+ void run() override
{
while(!mStopping)
{
@@ -83,7 +84,7 @@ void LLWatchdogEntry::start()
void LLWatchdogEntry::stop()
{
// this can happen very late in the shutdown sequence
- if (! LLWatchdog::wasDeleted())
+ if (!LLWatchdog::wasDeleted())
{
LLWatchdog::getInstance()->remove(this);
}
@@ -117,7 +118,7 @@ void LLWatchdogTimeout::setTimeout(F32 d)
mTimeout = d;
}
-void LLWatchdogTimeout::start(const std::string& state)
+void LLWatchdogTimeout::start(std::string_view state)
{
if (mTimeout == 0)
{
@@ -139,9 +140,9 @@ void LLWatchdogTimeout::stop()
mTimer.stop();
}
-void LLWatchdogTimeout::ping(const std::string& state)
+void LLWatchdogTimeout::ping(std::string_view state)
{
- if(!state.empty())
+ if (!state.empty())
{
mPingState = state;
}
@@ -151,7 +152,7 @@ void LLWatchdogTimeout::ping(const std::string& state)
// LLWatchdog
LLWatchdog::LLWatchdog()
:mSuspectsAccessMutex()
- ,mTimer(NULL)
+ ,mTimer(nullptr)
,mLastClockCount(0)
{
}
@@ -176,7 +177,7 @@ void LLWatchdog::remove(LLWatchdogEntry* e)
void LLWatchdog::init()
{
- if(!mSuspectsAccessMutex && !mTimer)
+ if (!mSuspectsAccessMutex && !mTimer)
{
mSuspectsAccessMutex = new LLMutex();
mTimer = new LLWatchdogTimerThread();
@@ -191,17 +192,17 @@ void LLWatchdog::init()
void LLWatchdog::cleanup()
{
- if(mTimer)
+ if (mTimer)
{
mTimer->stop();
delete mTimer;
- mTimer = NULL;
+ mTimer = nullptr;
}
- if(mSuspectsAccessMutex)
+ if (mSuspectsAccessMutex)
{
delete mSuspectsAccessMutex;
- mSuspectsAccessMutex = NULL;
+ mSuspectsAccessMutex = nullptr;
}
mLastClockCount = 0;
@@ -214,12 +215,12 @@ void LLWatchdog::run()
// Check the time since the last call to run...
// If the time elapsed is two times greater than the regualr sleep time
// reset the active timeouts.
- const U32 TIME_ELAPSED_MULTIPLIER = 2;
+ constexpr U32 TIME_ELAPSED_MULTIPLIER = 2;
U64 current_time = LLTimer::getTotalTime();
U64 current_run_delta = current_time - mLastClockCount;
mLastClockCount = current_time;
- if(current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER))
+ if (current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER))
{
LL_INFOS() << "Watchdog thread delayed: resetting entries." << LL_ENDL;
for (const auto& suspect : mSuspects)
@@ -233,7 +234,7 @@ void LLWatchdog::run()
std::find_if(mSuspects.begin(),
mSuspects.end(),
[](const LLWatchdogEntry* suspect){ return ! suspect->isAlive(); });
- if(result != mSuspects.end())
+ if (result != mSuspects.end())
{
// error!!!
if(mTimer)
@@ -251,7 +252,7 @@ void LLWatchdog::run()
void LLWatchdog::lockThread()
{
- if(mSuspectsAccessMutex != NULL)
+ if (mSuspectsAccessMutex)
{
mSuspectsAccessMutex->lock();
}
@@ -259,7 +260,7 @@ void LLWatchdog::lockThread()
void LLWatchdog::unlockThread()
{
- if(mSuspectsAccessMutex != NULL)
+ if (mSuspectsAccessMutex)
{
mSuspectsAccessMutex->unlock();
}
diff --git a/indra/newview/llwatchdog.h b/indra/newview/llwatchdog.h
index fe8932e298..1931c582b0 100644
--- a/indra/newview/llwatchdog.h
+++ b/indra/newview/llwatchdog.h
@@ -56,14 +56,14 @@ public:
LLWatchdogTimeout();
virtual ~LLWatchdogTimeout();
- /* virtual */ bool isAlive() const;
- /* virtual */ void reset();
- /* virtual */ void start() { start(""); }
- /* virtual */ void stop();
+ bool isAlive() const override;
+ void reset() override;
+ void start() override { start(""); }
+ void stop() override;
- void start(const std::string& state);
+ void start(std::string_view state);
void setTimeout(F32 d);
- void ping(const std::string& state);
+ void ping(std::string_view state);
const std::string& getState() {return mPingState; }
private:
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index 8ce1a745c3..89fd93d58d 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -33,7 +33,6 @@
#include "llagentwearables.h"
#include "llappearancemgr.h"
-#include "llinventoryfunctions.h"
#include "llinventoryicon.h"
#include "llgesturemgr.h"
#include "lltransutil.h"
@@ -41,14 +40,6 @@
#include "llviewermenu.h"
#include "llvoavatarself.h"
-class LLFindOutfitItems : public LLInventoryCollectFunctor
-{
-public:
- LLFindOutfitItems() {}
- virtual ~LLFindOutfitItems() {}
- virtual bool operator()(LLInventoryCategory* cat,
- LLInventoryItem* item);
-};
bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
@@ -894,7 +885,7 @@ void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, LLWearableTyp
}
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
- registrar.add("Wearable.CreateNew", boost::bind(createNewWearableByType, w_type));
+ registrar.add("Wearable.CreateNew", { boost::bind(createNewWearableByType, w_type), cb_info::UNTRUSTED_THROTTLE });
menup = createFromFile("menu_wearable_list_item.xml");
if (!menup)
{
@@ -920,7 +911,7 @@ void LLWearableItemsList::ContextMenu::show(LLView* spawning_view, LLWearableTyp
// virtual
LLContextMenu* LLWearableItemsList::ContextMenu::createMenu()
{
- LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::ScopedRegistrarHelper registrar;
const uuid_vec_t& ids = mUUIDs; // selected items IDs
LLUUID selected_id = ids.front(); // ID of the first selected item
@@ -942,6 +933,7 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu()
// Register handlers for attachments.
registrar.add("Attachment.Detach",
boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids, no_op));
+ registrar.add("Attachment.Favorite", boost::bind(toggle_favorites, ids));
registrar.add("Attachment.Touch", boost::bind(handle_attachment_touch, selected_id));
registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id));
registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2));
@@ -973,8 +965,11 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
U32 n_links = 0; // number of links among the selected items
U32 n_editable = 0; // number of editable items among the selected ones
U32 n_touchable = 0; // number of touchable items among the selected ones
+ U32 n_favorites = 0; // number of favorite items among the selected ones
bool can_be_worn = true;
+ bool can_favorite = false;
+ bool can_unfavorite = false;
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
{
@@ -996,6 +991,12 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
const bool is_editable = get_is_item_editable(id);
const bool is_touchable = enable_attachment_touch(id);
const bool is_already_worn = gAgentWearables.selfHasWearable(wearable_type);
+
+ LLUUID linked_id = item->getLinkedUUID();
+ LLViewerInventoryItem* linked_item = gInventory.getItem(linked_id);
+ can_favorite |= !linked_item->getIsFavorite();
+ can_unfavorite |= linked_item->getIsFavorite();
+
if (is_worn)
{
++n_worn;
@@ -1019,7 +1020,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
if (can_be_worn)
{
- can_be_worn = get_can_item_be_worn(item->getLinkedUUID());
+ can_be_worn = get_can_item_be_worn(linked_id);
}
} // for
@@ -1041,6 +1042,8 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
setMenuItemEnabled(menu, "create_new", LLAppearanceMgr::instance().canAddWearables(ids));
setMenuItemVisible(menu, "show_original", !standalone);
setMenuItemEnabled(menu, "show_original", n_items == 1 && n_links == n_items);
+ setMenuItemVisible(menu, "favorites_add", can_favorite);
+ setMenuItemVisible(menu, "favorites_remove", can_unfavorite);
setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items);
setMenuItemVisible(menu, "detach", mask == MASK_ATTACHMENT && n_worn == n_items);
setMenuItemVisible(menu, "take_off_or_detach", mask == (MASK_ATTACHMENT|MASK_CLOTHING));
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index 3fe1059176..1a22d6b366 100644
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -32,6 +32,7 @@
#include "llsingleton.h"
// newview
+#include "llinventoryfunctions.h"
#include "llinventoryitemslist.h"
#include "llinventorylistitem.h"
#include "lllistcontextmenu.h"
@@ -507,4 +508,11 @@ protected:
LLWearableType::EType mMenuWearableType;
};
+struct LLFindOutfitItems : public LLInventoryCollectFunctor
+{
+ LLFindOutfitItems() {}
+ virtual ~LLFindOutfitItems() {}
+ virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item);
+};
+
#endif //LL_LLWEARABLEITEMSLIST_H
diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp
index ebcdd537a5..601abdf5cf 100644
--- a/indra/newview/llwindowlistener.cpp
+++ b/indra/newview/llwindowlistener.cpp
@@ -54,7 +54,7 @@ LLWindowListener::LLWindowListener(LLViewerWindow *window, const KeyboardGetter&
"Given [\"keysym\"], [\"keycode\"] or [\"char\"], inject the specified ";
std::string keyExplain =
"(integer keycode values, or keysym string from any addKeyName() call in\n"
- "http://bitbucket.org/lindenlab/viewer-release/src/tip/indra/llwindow/llkeyboard.cpp )\n";
+ "https://github.com/secondlife/viewer/blob/main/indra/llwindow/llkeyboard.cpp#L68-L124)\n";
std::string mask =
"Specify optional [\"mask\"] as an array containing any of \"CTL\", \"ALT\",\n"
"\"SHIFT\" or \"MAC_CONTROL\"; the corresponding modifier bits will be combined\n"
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index 7962c28e6d..2fd45337fc 100644
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -32,6 +32,7 @@
#include "message.h"
#include "lltracker.h"
#include "lluistring.h"
+#include "llviewercontrol.h"
#include "llviewertexturelist.h"
#include "lltrans.h"
#include "llgltexture.h"
@@ -117,6 +118,7 @@ LLVector3d LLSimInfo::getGlobalOrigin() const
{
return from_region_handle(mHandle);
}
+
LLVector3 LLSimInfo::getLocalPos(LLVector3d global_pos) const
{
LLVector3d sim_origin = from_region_handle(mHandle);
@@ -492,9 +494,20 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID&
case MAP_ITEM_MATURE_EVENT:
case MAP_ITEM_ADULT_EVENT:
{
- std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:["
- +LLTrans::getString ("TimeMin")+"] ["
- +LLTrans::getString ("TimeAMPM")+"]";
+ std::string timeStr;
+
+ static bool use_24h = gSavedSettings.getBOOL("Use24HourClock");
+ if (use_24h)
+ {
+ std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:["
+ + LLTrans::getString("TimeMin") + "]";
+ }
+ else
+ {
+ std::string timeStr = "[" + LLTrans::getString("TimeHour12") + "]:["
+ + LLTrans::getString("TimeMin") + "] ["
+ + LLTrans::getString("TimeAMPM") + "]";
+ }
LLSD substitution;
substitution["datetime"] = (S32) extra;
LLStringUtil::format (timeStr, substitution);
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 6b2bd3e6fb..1be6a6cfff 100755
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -517,26 +517,38 @@ void LLWorldMapView::draw()
// Draw the region name in the lower left corner
if (mMapScale >= DRAW_TEXT_THRESHOLD)
{
- std::string mesg;
+ static LLCachedControl<bool> print_coords(gSavedSettings, "MapShowGridCoords");
+ static LLFontGL* font = LLFontGL::getFontSansSerifSmallBold();
+
+ auto print = [&](std::string text, F32 x, F32 y, bool use_ellipses)
+ {
+ font->renderUTF8(text, 0,
+ (F32)llfloor(left + x), (F32)llfloor(bottom + y),
+ LLColor4::white,
+ LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW,
+ S32_MAX, //max_chars
+ (S32)mMapScale, //max_pixels
+ NULL,
+ use_ellipses);
+ };
+
+ std::string grid_name = info->getName();
if (info->isDown())
{
- mesg = llformat( "%s (%s)", info->getName().c_str(), sStringsMap["offline"].c_str());
+ grid_name += " (" + sStringsMap["offline"] + ")";
}
- else
+
+ if (print_coords)
{
- mesg = info->getName();
+ print(grid_name, 3, 14, true);
+ // Obtain and print the grid map coordinates
+ LLVector3d region_pos = info->getGlobalOrigin();
+ std::string grid_coords = llformat("[%.0f, %.0f]", region_pos[VX] / 256, region_pos[VY] / 256);
+ print(grid_coords, 3, 2, false);
}
- if (!mesg.empty())
+ else
{
- LLFontGL::getFontSansSerifSmallBold()->renderUTF8(
- mesg, 0,
- (F32)llfloor(left + 3), (F32)llfloor(bottom + 2),
- LLColor4::white,
- LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW,
- S32_MAX, //max_chars
- (S32)mMapScale, //max_pixels
- NULL,
- /*use_ellipses*/true);
+ print(grid_name, 3, 2, true);
}
}
}
diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp
index 78151ebd1c..3c1268cd26 100644
--- a/indra/newview/llworldmipmap.cpp
+++ b/indra/newview/llworldmipmap.cpp
@@ -30,7 +30,7 @@
#include "llviewercontrol.h" // LLControlGroup
#include "llviewertexturelist.h"
-#include "math.h" // log()
+#include <cmath> // log()
// Turn this on to output tile stats in the standard output
#define DEBUG_TILES_STAT 0
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 07e2b118d3..0f956d8350 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -218,7 +218,7 @@ LLXMLRPCTransaction::Impl::Impl
mCertStore = gSavedSettings.getString("CertStore");
httpOpts->setSSLVerifyPeer(vefifySSLCert);
- httpOpts->setSSLVerifyHost(vefifySSLCert ? 2 : 0);
+ httpOpts->setSSLVerifyHost(vefifySSLCert);
// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index f95090d134..41265c2202 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -126,7 +126,7 @@
#define A_GCC 1
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-variable"
-#if LL_LINUX
+#if LL_LINUX && defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic ignored "-Wrestrict"
#endif
#endif
@@ -139,7 +139,6 @@ bool gShiftFrame = false;
//cached settings
bool LLPipeline::WindLightUseAtmosShaders;
bool LLPipeline::RenderDeferred;
-F32 LLPipeline::RenderDeferredSunWash;
U32 LLPipeline::RenderFSAAType;
U32 LLPipeline::RenderResolutionDivisor;
bool LLPipeline::RenderUIBuffer;
@@ -180,7 +179,6 @@ F32 LLPipeline::CameraFocusTransitionTime;
F32 LLPipeline::CameraFNumber;
F32 LLPipeline::CameraFocalLength;
F32 LLPipeline::CameraFieldOfView;
-F32 LLPipeline::RenderShadowNoise;
F32 LLPipeline::RenderShadowBlurSize;
F32 LLPipeline::RenderSSAOScale;
U32 LLPipeline::RenderSSAOMaxScale;
@@ -193,8 +191,6 @@ F32 LLPipeline::RenderShadowBias;
F32 LLPipeline::RenderSpotShadowOffset;
F32 LLPipeline::RenderSpotShadowBias;
LLDrawable* LLPipeline::RenderSpotLight = nullptr;
-F32 LLPipeline::RenderEdgeDepthCutoff;
-F32 LLPipeline::RenderEdgeNormCutoff;
LLVector3 LLPipeline::RenderShadowGaussian;
F32 LLPipeline::RenderShadowBlurDistFactor;
bool LLPipeline::RenderDeferredAtmospheric;
@@ -277,7 +273,6 @@ static LLTrace::BlockTimerStatHandle FTM_STATESORT_DRAWABLE("Sort Drawables");
static LLStaticHashedString sTint("tint");
static LLStaticHashedString sAmbiance("ambiance");
static LLStaticHashedString sAlphaScale("alpha_scale");
-static LLStaticHashedString sNormMat("norm_mat");
static LLStaticHashedString sOffset("offset");
static LLStaticHashedString sScreenRes("screenRes");
static LLStaticHashedString sDelta("delta");
@@ -502,7 +497,6 @@ void LLPipeline::init()
connectRefreshCachedSettingsSafe("UseOcclusion");
// DEPRECATED -- connectRefreshCachedSettingsSafe("WindLightUseAtmosShaders");
// DEPRECATED -- connectRefreshCachedSettingsSafe("RenderDeferred");
- connectRefreshCachedSettingsSafe("RenderDeferredSunWash");
connectRefreshCachedSettingsSafe("RenderFSAAType");
connectRefreshCachedSettingsSafe("RenderResolutionDivisor");
connectRefreshCachedSettingsSafe("RenderUIBuffer");
@@ -543,7 +537,6 @@ void LLPipeline::init()
connectRefreshCachedSettingsSafe("CameraFNumber");
connectRefreshCachedSettingsSafe("CameraFocalLength");
connectRefreshCachedSettingsSafe("CameraFieldOfView");
- connectRefreshCachedSettingsSafe("RenderShadowNoise");
connectRefreshCachedSettingsSafe("RenderShadowBlurSize");
connectRefreshCachedSettingsSafe("RenderSSAOScale");
connectRefreshCachedSettingsSafe("RenderSSAOMaxScale");
@@ -555,8 +548,6 @@ void LLPipeline::init()
connectRefreshCachedSettingsSafe("RenderShadowBias");
connectRefreshCachedSettingsSafe("RenderSpotShadowOffset");
connectRefreshCachedSettingsSafe("RenderSpotShadowBias");
- connectRefreshCachedSettingsSafe("RenderEdgeDepthCutoff");
- connectRefreshCachedSettingsSafe("RenderEdgeNormCutoff");
connectRefreshCachedSettingsSafe("RenderShadowGaussian");
connectRefreshCachedSettingsSafe("RenderShadowBlurDistFactor");
connectRefreshCachedSettingsSafe("RenderDeferredAtmospheric");
@@ -577,6 +568,7 @@ void LLPipeline::init()
connectRefreshCachedSettingsSafe("RenderScreenSpaceReflectionAdaptiveStepMultiplier");
connectRefreshCachedSettingsSafe("RenderScreenSpaceReflectionGlossySamples");
connectRefreshCachedSettingsSafe("RenderBufferVisualization");
+ connectRefreshCachedSettingsSafe("RenderBufferClearOnInvalidate");
connectRefreshCachedSettingsSafe("RenderMirrors");
connectRefreshCachedSettingsSafe("RenderHeroProbeUpdateRate");
connectRefreshCachedSettingsSafe("RenderHeroProbeConservativeUpdateMultiplier");
@@ -1019,7 +1011,6 @@ void LLPipeline::refreshCachedSettings()
WindLightUseAtmosShaders = true; // DEPRECATED -- gSavedSettings.getBOOL("WindLightUseAtmosShaders");
RenderDeferred = true; // DEPRECATED -- gSavedSettings.getBOOL("RenderDeferred");
- RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash");
RenderFSAAType = gSavedSettings.getU32("RenderFSAAType");
RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor");
RenderUIBuffer = gSavedSettings.getBOOL("RenderUIBuffer");
@@ -1060,7 +1051,6 @@ void LLPipeline::refreshCachedSettings()
CameraFNumber = gSavedSettings.getF32("CameraFNumber");
CameraFocalLength = gSavedSettings.getF32("CameraFocalLength");
CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView");
- RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise");
RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize");
RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale");
RenderSSAOMaxScale = gSavedSettings.getU32("RenderSSAOMaxScale");
@@ -1072,8 +1062,6 @@ void LLPipeline::refreshCachedSettings()
RenderShadowBias = gSavedSettings.getF32("RenderShadowBias");
RenderSpotShadowOffset = gSavedSettings.getF32("RenderSpotShadowOffset");
RenderSpotShadowBias = gSavedSettings.getF32("RenderSpotShadowBias");
- RenderEdgeDepthCutoff = gSavedSettings.getF32("RenderEdgeDepthCutoff");
- RenderEdgeNormCutoff = gSavedSettings.getF32("RenderEdgeNormCutoff");
RenderShadowGaussian = gSavedSettings.getVector3("RenderShadowGaussian");
RenderShadowBlurDistFactor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
RenderDeferredAtmospheric = gSavedSettings.getBOOL("RenderDeferredAtmospheric");
@@ -1094,6 +1082,7 @@ void LLPipeline::refreshCachedSettings()
RenderScreenSpaceReflectionAdaptiveStepMultiplier = gSavedSettings.getF32("RenderScreenSpaceReflectionAdaptiveStepMultiplier");
RenderScreenSpaceReflectionGlossySamples = gSavedSettings.getS32("RenderScreenSpaceReflectionGlossySamples");
RenderBufferVisualization = gSavedSettings.getS32("RenderBufferVisualization");
+ LLRenderTarget::sClearOnInvalidate = gSavedSettings.getBOOL("RenderBufferClearOnInvalidate");
RenderMirrors = gSavedSettings.getBOOL("RenderMirrors");
RenderHeroProbeUpdateRate = gSavedSettings.getS32("RenderHeroProbeUpdateRate");
RenderHeroProbeConservativeUpdateMultiplier = gSavedSettings.getS32("RenderHeroProbeConservativeUpdateMultiplier");
@@ -3485,8 +3474,6 @@ void LLPipeline::postSort(LLCamera &camera)
assertInitialized();
- LL_PUSH_CALLSTACKS();
-
if (!gCubeSnapshot)
{
// rebuild drawable geometry
@@ -3502,15 +3489,12 @@ void LLPipeline::postSort(LLCamera &camera)
group->rebuildGeom();
}
}
- LL_PUSH_CALLSTACKS();
// rebuild groups
sCull->assertDrawMapsEmpty();
rebuildPriorityGroups();
}
- LL_PUSH_CALLSTACKS();
-
// build render map
for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
{
@@ -3631,7 +3615,6 @@ void LLPipeline::postSort(LLCamera &camera)
std::sort(sCull->beginRiggedAlphaGroups(), sCull->endRiggedAlphaGroups(), LLSpatialGroup::CompareRenderOrder());
}
- LL_PUSH_CALLSTACKS();
// only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender && !gCubeSnapshot)
{
@@ -3684,7 +3667,7 @@ void LLPipeline::postSort(LLCamera &camera)
forAllVisibleDrawables(renderSoundHighlights);
}
}
- LL_PUSH_CALLSTACKS();
+
// If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
if (LLFloaterTelehub::renderBeacons() && !sShadowRender && !gCubeSnapshot)
{
@@ -3745,7 +3728,6 @@ void LLPipeline::postSort(LLCamera &camera)
LLVertexBuffer::flushBuffers();
// LLSpatialGroup::sNoDelete = false;
- LL_PUSH_CALLSTACKS();
}
@@ -7201,7 +7183,7 @@ void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget*
LLRenderTarget& depth_src = mRT->deferredScreen;
dst->bindTarget();
- dst->clear();
+ dst->invalidate();
gCopyDepthProgram.bind();
S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP);
@@ -7388,7 +7370,7 @@ void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst)
// bake out texture2D with RGBL for FXAA shader
mFXAAMap.bindTarget();
- mFXAAMap.clear(GL_COLOR_BUFFER_BIT);
+ mFXAAMap.invalidate(GL_COLOR_BUFFER_BIT);
shader = &gGlowCombineFXAAProgram;
shader->bind();
@@ -7487,6 +7469,7 @@ void LLPipeline::generateSMAABuffers(LLRenderTarget* src)
LLGLSLShader& edge_shader = gSMAAEdgeDetectProgram[fsaa_quality];
dest.bindTarget();
+ // SMAA utilizes discard, so the background color matters
dest.clear(GL_COLOR_BUFFER_BIT);
edge_shader.bind();
@@ -7530,7 +7513,7 @@ void LLPipeline::generateSMAABuffers(LLRenderTarget* src)
LLGLSLShader& blend_weights_shader = gSMAABlendWeightsProgram[fsaa_quality];
dest.bindTarget();
- dest.clear(GL_COLOR_BUFFER_BIT);
+ dest.invalidate(GL_COLOR_BUFFER_BIT);
blend_weights_shader.bind();
blend_weights_shader.uniform4fv(sSmaaRTMetrics, 1, rt_metrics);
@@ -7606,7 +7589,7 @@ void LLPipeline::applySMAA(LLRenderTarget* src, LLRenderTarget* dst)
LLGLSLShader& blend_shader = gSMAANeighborhoodBlendProgram[fsaa_quality];
bound_target->bindTarget();
- bound_target->clear(GL_COLOR_BUFFER_BIT);
+ bound_target->invalidate(GL_COLOR_BUFFER_BIT);
blend_shader.bind();
blend_shader.uniform4fv(sSmaaRTMetrics, 1, rt_metrics);
@@ -7803,8 +7786,6 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst)
gDeferredCoFProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, src, LLTexUnit::TFO_POINT);
gDeferredCoFProgram.bindTexture(LLShaderMgr::DEFERRED_DEPTH, &mRT->deferredScreen, true);
- gDeferredCoFProgram.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
- gDeferredCoFProgram.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
gDeferredCoFProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, (GLfloat)dst->getWidth(), (GLfloat)dst->getHeight());
gDeferredCoFProgram.uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f);
gDeferredCoFProgram.uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant);
@@ -8116,32 +8097,11 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
stop_glerror();
}
- channel = shader.enableTexture(LLShaderMgr::EXPOSURE_MAP);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bind(&mExposureMap);
- }
-
- if (shader.getUniformLocation(LLShaderMgr::VIEWPORT) != -1)
- {
- shader.uniform4f(LLShaderMgr::VIEWPORT, (F32) gGLViewport[0],
- (F32) gGLViewport[1],
- (F32) gGLViewport[2],
- (F32) gGLViewport[3]);
- }
-
if (sReflectionRender && !shader.getUniformLocation(LLShaderMgr::MODELVIEW_MATRIX))
{
shader.uniformMatrix4fv(LLShaderMgr::MODELVIEW_MATRIX, 1, false, glm::value_ptr(mReflectionModelView));
}
- channel = shader.enableTexture(LLShaderMgr::DEFERRED_NOISE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
bindLightFunc(shader);
stop_glerror();
@@ -8205,34 +8165,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
bindReflectionProbes(shader);
- if (gAtmosphere)
- {
- // bind precomputed textures necessary for calculating sun and sky luminance
- channel = shader.enableTexture(LLShaderMgr::TRANSMITTANCE_TEX, LLTexUnit::TT_TEXTURE);
- if (channel > -1)
- {
- shader.bindTexture(LLShaderMgr::TRANSMITTANCE_TEX, gAtmosphere->getTransmittance());
- }
-
- channel = shader.enableTexture(LLShaderMgr::SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D);
- if (channel > -1)
- {
- shader.bindTexture(LLShaderMgr::SCATTER_TEX, gAtmosphere->getScattering());
- }
-
- channel = shader.enableTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D);
- if (channel > -1)
- {
- shader.bindTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, gAtmosphere->getMieScattering());
- }
-
- channel = shader.enableTexture(LLShaderMgr::ILLUMINANCE_TEX, LLTexUnit::TT_TEXTURE);
- if (channel > -1)
- {
- shader.bindTexture(LLShaderMgr::ILLUMINANCE_TEX, gAtmosphere->getIlluminance());
- }
- }
-
/*if (gCubeSnapshot)
{ // we only really care about the first two values, but the shader needs increasing separation between clip planes
shader.uniform4f(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1.f, 64.f, 128.f, 256.f);
@@ -8241,26 +8173,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
{
shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV);
}
- shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash);
- shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise);
- shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize);
-
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale);
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, (GLfloat)RenderSSAOMaxScale);
-
- F32 ssao_factor = RenderSSAOFactor;
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor);
- shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0f/ssao_factor);
-
- LLVector3 ssao_effect = RenderSSAOEffect;
- F32 matrix_diag = (ssao_effect[0] + 2.0f*ssao_effect[1])/3.0f;
- F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0f;
- // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
- // value factor, and scales remainder by saturation factor
- F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
- matrix_nondiag, matrix_diag, matrix_nondiag,
- matrix_nondiag, matrix_nondiag, matrix_diag};
- shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat);
//F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
F32 shadow_bias_error = RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2])/3000.f;
@@ -8277,20 +8189,12 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
shader.uniform3fv(LLShaderMgr::DEFERRED_MOON_DIR, 1, mTransformedMoonDir.mV);
shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, (GLfloat)mRT->shadow[0].getWidth(), (GLfloat)mRT->shadow[0].getHeight());
shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, (GLfloat)mSpotShadow[0].getWidth(), (GLfloat)mSpotShadow[0].getHeight());
- shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
- shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
shader.uniformMatrix4fv(LLShaderMgr::MODELVIEW_DELTA_MATRIX, 1, GL_FALSE, glm::value_ptr(gGLDeltaModelView));
shader.uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_DELTA_MATRIX, 1, GL_FALSE, glm::value_ptr(gGLInverseDeltaModelView));
shader.uniform1i(LLShaderMgr::CUBE_SNAPSHOT, gCubeSnapshot ? 1 : 0);
- if (shader.getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
- {
- glm::mat4 norm_mat = glm::transpose(glm::inverse(get_current_modelview()));
- shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, false, glm::value_ptr(norm_mat));
- }
-
// auto adjust legacy sun color if needed
static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
static LLCachedControl<F32> auto_adjust_sun_color_scale(gSavedSettings, "RenderSkyAutoAdjustSunColorScale", 1.f);
@@ -8384,20 +8288,37 @@ void LLPipeline::renderDeferredLighting()
LLGLSLShader& sun_shader = gCubeSnapshot ? gDeferredSunProbeProgram : gDeferredSunProgram;
bindDeferredShader(sun_shader, deferred_light_target);
mScreenTriangleVB->setBuffer();
- glClearColor(1, 1, 1, 1);
- deferred_light_target->clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0, 0, 0, 0);
+ deferred_light_target->invalidate(GL_COLOR_BUFFER_BIT);
sun_shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES,
(GLfloat)deferred_light_target->getWidth(),
(GLfloat)deferred_light_target->getHeight());
+ if (RenderDeferredSSAO && !gCubeSnapshot)
+ {
+ sun_shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_RADIUS, RenderSSAOScale);
+ sun_shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_MAX_RADIUS, (GLfloat)RenderSSAOMaxScale);
+
+ F32 ssao_factor = RenderSSAOFactor;
+ sun_shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor);
+ sun_shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0f / ssao_factor);
+
+ S32 channel = sun_shader.enableTexture(LLShaderMgr::DEFERRED_NOISE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+ }
+
{
LLGLDisable blend(GL_BLEND);
LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
}
+ sun_shader.disableTexture(LLShaderMgr::DEFERRED_NOISE);
+
unbindDeferredShader(sun_shader);
}
deferred_light_target->flush();
@@ -8410,9 +8331,7 @@ void LLPipeline::renderDeferredLighting()
LL_PROFILE_GPU_ZONE("soften shadow");
// blur lightmap
screen_target->bindTarget();
- glClearColor(1, 1, 1, 1);
- screen_target->clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0, 0, 0, 0);
+ screen_target->invalidate(GL_COLOR_BUFFER_BIT);
bindDeferredShader(gDeferredBlurLightProgram);
@@ -8464,7 +8383,6 @@ void LLPipeline::renderDeferredLighting()
deferred_light_target->flush();
unbindDeferredShader(gDeferredBlurLightProgram);
}
-
screen_target->bindTarget();
// clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
glClearColor(0, 0, 0, 0);
@@ -8492,6 +8410,19 @@ void LLPipeline::renderDeferredLighting()
soften_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
+ if(RenderDeferredSSAO)
+ {
+ LLVector3 ssao_effect = RenderSSAOEffect;
+ F32 matrix_diag = (ssao_effect[0] + 2.0f * ssao_effect[1]) / 3.0f;
+ F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1]) / 3.0f;
+ // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
+ // value factor, and scales remainder by saturation factor
+ F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
+ matrix_nondiag, matrix_diag, matrix_nondiag,
+ matrix_nondiag, matrix_nondiag, matrix_diag };
+ soften_shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_SSAO_EFFECT_MAT, 1, GL_FALSE, ssao_effect_mat);
+ }
+
{
LLGLDepthTest depth(GL_FALSE);
LLGLDisable blend(GL_BLEND);
@@ -8724,13 +8655,12 @@ void LLPipeline::renderDeferredLighting()
LLDrawable* drawablep = *iter;
LLVOVolume* volume = drawablep->getVOVolume();
LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
F32 light_size_final = volume->getLightRadius() * 1.5f;
F32 light_falloff_final = volume->getLightFalloff(DEFERRED_LIGHT_FALLOFF);
sVisibleLightCount++;
- glm::vec3 tc(glm::make_vec3(c));
+ glm::vec3 tc(glm::make_vec3(LLVector4(center).mV));
tc = mul_mat4_vec3(mat, tc);
setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
@@ -9114,7 +9044,6 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_target->getUsage());
shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, deferred_light_target->getUsage());
shader.disableTexture(LLShaderMgr::DIFFUSE_MAP);
- shader.disableTexture(LLShaderMgr::DEFERRED_BLOOM);
for (U32 i = 0; i < 4; i++)
{
@@ -9132,7 +9061,6 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
}
}
- shader.disableTexture(LLShaderMgr::DEFERRED_NOISE);
shader.disableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC);
if (!LLPipeline::sReflectionProbesEnabled)
@@ -10278,7 +10206,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
view[j] = glm::inverse(view[j]);
//llassert(origin.isFinite());
- glm::vec3 origin_agent(glm::make_vec3(origin.mV));
+ glm::vec3 origin_agent(glm::make_vec3(LLVector4(origin).mV));
//translate view to origin
origin_agent = mul_mat4_vec3(view[j], origin_agent);
@@ -11368,21 +11296,24 @@ public:
}
};
-
+// Called from LLViewHighlightTransparent when "Highlight Transparent" is toggled
void LLPipeline::rebuildDrawInfo()
{
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ const U32 types_to_traverse[] =
{
- LLViewerRegion* region = *iter;
-
- LLOctreeDirty dirty;
-
- LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_VOLUME);
- dirty.traverse(part->mOctree);
+ LLViewerRegion::PARTITION_VOLUME,
+ LLViewerRegion::PARTITION_BRIDGE,
+ LLViewerRegion::PARTITION_AVATAR
+ };
- part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
- dirty.traverse(part->mOctree);
+ LLOctreeDirty dirty;
+ for (LLViewerRegion* region : LLWorld::getInstance()->getRegionList())
+ {
+ for (U32 type : types_to_traverse)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(type);
+ dirty.traverse(part->mOctree);
+ }
}
}
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 5c9b95ef4a..c69ca863e7 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -1000,7 +1000,6 @@ public:
//cached settings
static bool WindLightUseAtmosShaders;
static bool RenderDeferred;
- static F32 RenderDeferredSunWash;
static U32 RenderFSAAType;
static U32 RenderResolutionDivisor;
static bool RenderUIBuffer;
@@ -1042,7 +1041,6 @@ public:
static F32 CameraFNumber;
static F32 CameraFocalLength;
static F32 CameraFieldOfView;
- static F32 RenderShadowNoise;
static F32 RenderShadowBlurSize;
static F32 RenderSSAOScale;
static U32 RenderSSAOMaxScale;
@@ -1055,8 +1053,6 @@ public:
static F32 RenderSpotShadowOffset;
static F32 RenderSpotShadowBias;
static LLDrawable* RenderSpotLight;
- static F32 RenderEdgeDepthCutoff;
- static F32 RenderEdgeNormCutoff;
static LLVector3 RenderShadowGaussian;
static F32 RenderShadowBlurDistFactor;
static bool RenderDeferredAtmospheric;
diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp
new file mode 100644
index 0000000000..110beeafc0
--- /dev/null
+++ b/indra/newview/rlvactions.cpp
@@ -0,0 +1,42 @@
+/**
+ * @file rlvactions.cpp
+ * @author Kitty Barnett
+ * @brief RLVa public facing helper class to easily make RLV checks
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "rlvactions.h"
+#include "rlvhandler.h"
+
+// ============================================================================
+// Helper functions
+//
+
+bool RlvActions::isRlvEnabled()
+{
+ return RlvHandler::isEnabled();
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h
new file mode 100644
index 0000000000..cb0df95e37
--- /dev/null
+++ b/indra/newview/rlvactions.h
@@ -0,0 +1,46 @@
+/**
+ * @file rlvactions.h
+ * @author Kitty Barnett
+ * @brief RLVa public facing helper class to easily make RLV checks
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+// ============================================================================
+// RlvActions - developer-friendly non-RLVa code facing class, use in lieu of RlvHandler whenever possible
+//
+
+class RlvActions
+{
+ // ================
+ // Helper functions
+ // ================
+public:
+ /*
+ * Convenience function to check if RLVa is enabled without having to include rlvhandler.h
+ */
+ static bool isRlvEnabled();
+};
+
+// ============================================================================
diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp
new file mode 100644
index 0000000000..4140659715
--- /dev/null
+++ b/indra/newview/rlvcommon.cpp
@@ -0,0 +1,134 @@
+/**
+ * @file rlvcommon.h
+ * @author Kitty Barnett
+ * @brief RLVa helper functions and constants used throughout the viewer
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llagent.h"
+#include "llchat.h"
+#include "lldbstrings.h"
+#include "llversioninfo.h"
+#include "llviewermenu.h"
+#include "llviewerstats.h"
+#include "message.h"
+#include <boost/algorithm/string.hpp>
+
+#include "rlvcommon.h"
+
+#include "llviewercontrol.h"
+#include "rlvhandler.h"
+
+using namespace Rlv;
+
+// ============================================================================
+// RlvStrings
+//
+
+std::string Strings::getVersion(bool wants_legacy)
+{
+ return llformat("%s viewer v%d.%d.%d (RLVa %d.%d.%d)",
+ !wants_legacy ? "RestrainedLove" : "RestrainedLife",
+ SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch,
+ ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch);
+}
+
+std::string Strings::getVersionAbout()
+{
+ return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d",
+ SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch,
+ ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch, LLVersionInfo::instance().getBuild());
+}
+
+std::string Strings::getVersionNum()
+{
+ return llformat("%d%02d%02d%02d",
+ SpecVersion::Major, SpecVersion::Minor, SpecVersion::Patch, SpecVersion::Build);
+}
+
+std::string Strings::getVersionImplNum()
+{
+ return llformat("%d%02d%02d%02d",
+ ImplVersion::Major, ImplVersion::Minor, ImplVersion::Patch, ImplVersion::ImplId);
+}
+
+// ============================================================================
+// RlvUtil
+//
+
+void Util::menuToggleVisible()
+{
+ bool isTopLevel = gSavedSettings.getBOOL(Settings::TopLevelMenu);
+ bool isRlvEnabled = RlvHandler::isEnabled();
+
+ LLMenuGL* menuRLVaMain = gMenuBarView->findChildMenuByName("RLVa Main", false);
+ LLMenuGL* menuAdvanced = gMenuBarView->findChildMenuByName("Advanced", false);
+ LLMenuGL* menuRLVaEmbed= menuAdvanced->findChildMenuByName("RLVa Embedded", false);
+
+ gMenuBarView->setItemVisible("RLVa Main", isRlvEnabled && isTopLevel);
+ menuAdvanced->setItemVisible("RLVa Embedded", isRlvEnabled && !isTopLevel);
+
+ if ( isRlvEnabled && menuRLVaMain && menuRLVaEmbed &&
+ ( (isTopLevel && 1 == menuRLVaMain->getItemCount()) || (!isTopLevel && 1 == menuRLVaEmbed->getItemCount())) )
+ {
+ LLMenuGL* menuFrom = isTopLevel ? menuRLVaEmbed : menuRLVaMain;
+ LLMenuGL* menuTo = isTopLevel ? menuRLVaMain : menuRLVaEmbed;
+ while (LLMenuItemGL* pItem = menuFrom->getItem(1))
+ {
+ menuFrom->removeChild(pItem);
+ menuTo->addChild(pItem);
+ pItem->updateBranchParent(menuTo);
+ }
+ }
+}
+
+bool Util::parseStringList(const std::string& strInput, std::vector<std::string>& optionList, std::string_view strSeparator)
+{
+ if (!strInput.empty())
+ boost::split(optionList, strInput, boost::is_any_of(strSeparator));
+ return !optionList.empty();
+}
+
+bool Util::sendChatReply(S32 nChannel, const std::string& strUTF8Text)
+{
+ if (!isValidReplyChannel(nChannel))
+ return false;
+
+ // Copy/paste from send_chat_from_viewer()
+ gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gMessageSystem->nextBlockFast(_PREHASH_ChatData);
+ gMessageSystem->addStringFast(_PREHASH_Message, utf8str_truncate(strUTF8Text, MAX_MSG_STR_LEN));
+ gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT);
+ gMessageSystem->addS32("Channel", nChannel);
+ gAgent.sendReliableMessage();
+ add(LLStatViewer::CHAT_COUNT, 1);
+
+ return true;
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h
new file mode 100644
index 0000000000..6f1bbbbdc6
--- /dev/null
+++ b/indra/newview/rlvcommon.h
@@ -0,0 +1,72 @@
+/**
+ * @file rlvcommon.h
+ * @author Kitty Barnett
+ * @brief RLVa helper functions and constants used throughout the viewer
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "rlvdefines.h"
+
+namespace Rlv
+{
+ // ============================================================================
+ // RlvStrings
+ //
+
+ class Strings
+ {
+ public:
+ static std::string getVersion(bool wants_legacy);
+ static std::string getVersionAbout();
+ static std::string getVersionImplNum();
+ static std::string getVersionNum();
+ };
+
+ // ============================================================================
+ // RlvUtil
+ //
+
+ namespace Util
+ {
+ bool isValidReplyChannel(S32 nChannel, bool isLoopback = false);
+ void menuToggleVisible();
+ bool parseStringList(const std::string& strInput, std::vector<std::string>& optionList, std::string_view strSeparator = Constants::OptionSeparator);
+ bool sendChatReply(S32 nChannel, const std::string& strUTF8Text);
+ bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text);
+ };
+
+ inline bool Util::isValidReplyChannel(S32 nChannel, bool isLoopback)
+ {
+ return (nChannel > (!isLoopback ? 0 : -1)) && (CHAT_CHANNEL_DEBUG != nChannel);
+ }
+
+ inline bool Util::sendChatReply(const std::string& strChannel, const std::string& strUTF8Text)
+ {
+ S32 nChannel;
+ return LLStringUtil::convertToS32(strChannel, nChannel) ? sendChatReply(nChannel, strUTF8Text) : false;
+ }
+
+ // ============================================================================
+}
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
new file mode 100644
index 0000000000..0deb59cad0
--- /dev/null
+++ b/indra/newview/rlvdefines.h
@@ -0,0 +1,194 @@
+/**
+ * @file rlvdefines.h
+ * @author Kitty Barnett
+ * @brief RLVa common defines, constants and enums
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+// ============================================================================
+// Defines
+//
+
+// Defining these makes it easier if we ever need to change our tag
+#define RLV_WARNS LL_WARNS("RLV")
+#define RLV_INFOS LL_INFOS("RLV")
+#define RLV_DEBUGS LL_DEBUGS("RLV")
+#define RLV_ENDL LL_ENDL
+#define RLV_VERIFY(f) (f)
+
+#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+ // Make sure we halt execution on errors
+ #define RLV_ERRS LL_ERRS("RLV")
+ // Keep our asserts separate from LL's
+ #define RLV_ASSERT(f) if (!(f)) { RLV_ERRS << "ASSERT (" << #f << ")" << RLV_ENDL; }
+ #define RLV_ASSERT_DBG(f) RLV_ASSERT(f)
+#else
+ // Don't halt execution on errors in release
+ #define RLV_ERRS LL_WARNS("RLV")
+ // We don't want to check assertions in release builds
+ #ifdef RLV_DEBUG
+ #define RLV_ASSERT(f) RLV_VERIFY(f)
+ #define RLV_ASSERT_DBG(f)
+ #else
+ #define RLV_ASSERT(f)
+ #define RLV_ASSERT_DBG(f)
+ #endif // RLV_DEBUG
+#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+
+namespace Rlv
+{
+ // Version of the specification we report
+ namespace SpecVersion {
+ constexpr S32 Major = 4;
+ constexpr S32 Minor = 0;
+ constexpr S32 Patch = 0;
+ constexpr S32 Build = 0;
+ };
+
+ // RLVa implementation version
+ namespace ImplVersion {
+ constexpr S32 Major = 3;
+ constexpr S32 Minor = 0;
+ constexpr S32 Patch = 0;
+ constexpr S32 ImplId = 13;
+ };
+
+ namespace Constants
+ {
+ constexpr char CmdPrefix = '@';
+ constexpr char ConsolePrompt[] = "> ";
+ constexpr std::string_view OptionSeparator = ";";
+ }
+}
+
+// ============================================================================
+// Enumeration declarations
+//
+
+namespace Rlv
+{
+ enum class EBehaviour {
+ Version = 0,
+ VersionNew,
+ VersionNum,
+ GetCommand,
+
+ Count,
+ Unknown,
+ };
+
+ enum class EBehaviourOptionType
+ {
+ EmptyOrException, // Behaviour takes no parameters
+ Exception, // Behaviour requires an exception as a parameter
+ NoneOrException, // Behaviour takes either no parameters or an exception
+ };
+
+ enum class EParamType {
+ Unknown = 0x00,
+ Add = 0x01, // <param> == "n"|"add"
+ Remove = 0x02, // <param> == "y"|"rem"
+ Force = 0x04, // <param> == "force"
+ Reply = 0x08, // <param> == <number>
+ Clear = 0x10,
+ AddRem = Add | Remove
+ };
+
+ enum class ECmdRet {
+ Unknown = 0x0000, // Unknown error (should only be used internally)
+ Retained, // Command was retained
+ Succeeded = 0x0100, // Command executed successfully
+ SuccessUnset, // Command executed successfully (RLV_TYPE_REMOVE for an unrestricted behaviour)
+ SuccessDuplicate, // Command executed successfully (RLV_TYPE_ADD for an already restricted behaviour)
+ SuccessDeprecated, // Command executed successfully but has been marked as deprecated
+ SuccessDelayed, // Command parsed valid but will execute at a later time
+ Failed = 0x0200, // Command failed (general failure)
+ FailedSyntax, // Command failed (syntax error)
+ FailedOption, // Command failed (invalid option)
+ FailedParam, // Command failed (invalid param)
+ FailedLock, // Command failed (command is locked by another object)
+ FailedDisabled, // Command failed (command disabled by user)
+ FailedUnknown, // Command failed (unknown command)
+ FailedNoSharedRoot, // Command failed (missing #RLV)
+ FailedDeprecated, // Command failed (deprecated and no longer supported)
+ FailedNoBehaviour, // Command failed (force modifier on an object with no active restrictions)
+ FailedUnheldBehaviour, // Command failed (local modifier on an object that doesn't hold the base behaviour)
+ FailedBlocked, // Command failed (object is blocked)
+ FailedThrottled, // Command failed (throttled)
+ FailedNoProcessor // Command doesn't have a template processor define (legacy code)
+ };
+
+ enum class EExceptionCheck
+ {
+ Permissive, // Exception can be set by any object
+ Strict, // Exception must be set by all objects holding the restriction
+ Default, // Permissive or strict will be determined by currently enforced restrictions
+ };
+
+ // Replace&remove in c++23
+ template <typename E>
+ constexpr std::enable_if_t<std::is_enum_v<E> && !std::is_convertible_v<E, int>, std::underlying_type_t<E>> to_underlying(E e) noexcept
+ {
+ return static_cast<std::underlying_type_t<E>>(e);
+ }
+
+ template <typename E>
+ constexpr std::enable_if_t<std::is_enum_v<E> && !std::is_convertible_v<E, int>, bool> has_flag(E value, E flag) noexcept
+ {
+ return (to_underlying(value) & to_underlying(flag)) != 0;
+ }
+
+ constexpr bool isReturnCodeSuccess(ECmdRet eRet)
+ {
+ return (to_underlying(eRet) & to_underlying(ECmdRet::Succeeded)) == to_underlying(ECmdRet::Succeeded);
+ }
+
+ constexpr bool isReturnCodeFailed(ECmdRet eRet)
+ {
+ return (to_underlying(eRet) & to_underlying(ECmdRet::Failed)) == to_underlying(ECmdRet::Failed);
+ }
+}
+
+// ============================================================================
+// Settings
+//
+
+namespace Rlv
+{
+ namespace Settings
+ {
+ constexpr char Main[] = "RestrainedLove";
+ constexpr char Debug[] = "RestrainedLoveDebug";
+
+ constexpr char DebugHideUnsetDup[] = "RLVaDebugHideUnsetDuplicate";
+ constexpr char EnableExperimentalCommands[] = "RLVaExperimentalCommands";
+ constexpr char EnableIMQuery[] = "RLVaEnableIMQuery";
+ constexpr char EnableTempAttach[] = "RLVaEnableTemporaryAttachments";
+ constexpr char TopLevelMenu[] = "RLVaTopLevelMenu";
+ };
+
+};
+
+// ============================================================================
diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp
new file mode 100644
index 0000000000..8a074fd14d
--- /dev/null
+++ b/indra/newview/rlvfloaters.cpp
@@ -0,0 +1,122 @@
+/**
+ * @file rlvfloaters.cpp
+ * @author Kitty Barnett
+ * @brief RLVa floaters class implementations
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llagentdata.h"
+#include "llchatentry.h"
+#include "lltexteditor.h"
+#include "lltrans.h"
+#include "llvoavatarself.h"
+
+#include "rlvfloaters.h"
+#include "rlvhandler.h"
+
+using namespace Rlv;
+
+// ============================================================================
+// FloaterConsole
+//
+
+bool FloaterConsole::postBuild()
+{
+ mInputEdit = getChild<LLChatEntry>("console_input");
+ mInputEdit->setCommitCallback(std::bind(&FloaterConsole::onInput, this));
+ mInputEdit->setTextExpandedCallback(std::bind(&FloaterConsole::reshapeLayoutPanel, this));
+ mInputEdit->setFocus(true);
+ mInputEdit->setCommitOnFocusLost(false);
+
+ mInputPanel = getChild<LLLayoutPanel>("input_panel");
+ mInputEditPad = mInputPanel->getRect().getHeight() - mInputEdit->getRect().getHeight();
+
+ mOutputText = getChild<LLTextEditor>("console_output");
+ mOutputText->appendText(Constants::ConsolePrompt, false);
+
+ if (RlvHandler::isEnabled())
+ {
+ mCommandOutputConn = RlvHandler::instance().setCommandOutputCallback([this](const RlvCommand& rlvCmd, S32, const std::string strText)
+ {
+ if (rlvCmd.getObjectID() == gAgentID)
+ {
+ mOutputText->appendText(rlvCmd.getBehaviour() + ": ", true);
+ mOutputText->appendText(strText, false);
+ }
+ });
+ }
+
+ return true;
+}
+
+void FloaterConsole::onClose(bool fQuitting)
+{
+ if (RlvHandler::isEnabled())
+ {
+ RlvHandler::instance().processCommand(gAgentID, "clear", true);
+ }
+}
+
+void FloaterConsole::onInput()
+{
+ if (!isAgentAvatarValid())
+ {
+ return;
+ }
+
+ std::string strText = mInputEdit->getText();
+ LLStringUtil::trim(strText);
+
+ mOutputText->appendText(strText, false);
+ mInputEdit->setText(LLStringUtil::null);
+
+ if (!RlvHandler::isEnabled())
+ {
+ mOutputText->appendText(LLTrans::getString("RlvConsoleDisable"), true);
+ }
+ else if (strText.length() <= 3 || Constants::CmdPrefix != strText[0])
+ {
+ mOutputText->appendText(LLTrans::getString("RlvConsoleInvalidCmd"), true);
+ }
+ else
+ {
+ LLChat chat;
+ chat.mFromID = gAgentID;
+ chat.mChatType = CHAT_TYPE_OWNER;
+
+ RlvHandler::instance().handleSimulatorChat(strText, chat, gAgentAvatarp);
+
+ mOutputText->appendText(strText, true);
+ }
+
+ mOutputText->appendText(Constants::ConsolePrompt, true);
+}
+
+void FloaterConsole::reshapeLayoutPanel()
+{
+ mInputPanel->reshape(mInputPanel->getRect().getWidth(), mInputEdit->getRect().getHeight() + mInputEditPad, false);
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h
new file mode 100644
index 0000000000..8acfa43f28
--- /dev/null
+++ b/indra/newview/rlvfloaters.h
@@ -0,0 +1,68 @@
+/**
+ * @file rlvfloaters.h
+ * @author Kitty Barnett
+ * @brief RLVa floaters class implementations
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "llfloater.h"
+
+#include "rlvdefines.h"
+
+class LLChatEntry;
+class LLFloaterReg;
+class LLLayoutPanel;
+class LLTextEditor;
+class RlvCommand;
+class RlvHandler;
+
+namespace Rlv
+{
+ // ============================================================================
+ // FloaterConsole - debug console to allow command execution without the need for a script
+ //
+
+ class FloaterConsole : public LLFloater
+ {
+ friend class ::LLFloaterReg;
+ FloaterConsole(const LLSD& sdKey) : LLFloater(sdKey) {}
+
+ public:
+ bool postBuild() override;
+ void onClose(bool fQuitting) override;
+ protected:
+ void onInput();
+ void reshapeLayoutPanel();
+
+ private:
+ boost::signals2::scoped_connection mCommandOutputConn;
+ int mInputEditPad = 0;
+ LLLayoutPanel* mInputPanel = nullptr;
+ LLChatEntry* mInputEdit = nullptr;
+ LLTextEditor* mOutputText = nullptr;
+ };
+
+ // ============================================================================
+};
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
new file mode 100644
index 0000000000..6c4b439105
--- /dev/null
+++ b/indra/newview/rlvhandler.cpp
@@ -0,0 +1,225 @@
+/**
+ * @file rlvhandler.cpp
+ * @author Kitty Barnett
+ * @brief RLVa helper classes for internal use only
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llstartup.h"
+#include "llviewercontrol.h"
+#include "llviewerobject.h"
+
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+#include "rlvhelper.h"
+
+#include <boost/algorithm/string.hpp>
+
+using namespace Rlv;
+
+// ============================================================================
+// Static variable initialization
+//
+
+bool RlvHandler::mIsEnabled = false;
+
+// ============================================================================
+// Command processing functions
+//
+
+bool RlvHandler::handleSimulatorChat(std::string& message, const LLChat& chat, const LLViewerObject* chatObj)
+{
+ // *TODO: There's an edge case for temporary attachments when going from enabled -> disabled with restrictions already in place
+ static LLCachedControl<bool> enable_temp_attach(gSavedSettings, Settings::EnableTempAttach);
+ static LLCachedControl<bool> show_debug_output(gSavedSettings, Settings::Debug);
+ static LLCachedControl<bool> hide_unset_dupes(gSavedSettings, Settings::DebugHideUnsetDup);
+
+ if ( message.length() <= 3 || Constants::CmdPrefix != message[0] || CHAT_TYPE_OWNER != chat.mChatType ||
+ (chatObj && chatObj->isTempAttachment() && !enable_temp_attach()) )
+ {
+ return false;
+ }
+
+ message.erase(0, 1);
+ LLStringUtil::toLower(message);
+ CommandDbgOut cmdDbgOut(message, chatObj->getID() == gAgentID);
+
+ boost_tokenizer tokens(message, boost::char_separator<char>(",", "", boost::drop_empty_tokens));
+ for (const std::string& strCmd : tokens)
+ {
+ ECmdRet eRet = processCommand(chat.mFromID, strCmd, true);
+ if ( show_debug_output() &&
+ (!hide_unset_dupes() || (ECmdRet::SuccessUnset != eRet && ECmdRet::SuccessDuplicate != eRet)) )
+ {
+ cmdDbgOut.add(strCmd, eRet);
+ }
+ }
+
+ message = cmdDbgOut.get();
+ return true;
+}
+
+ECmdRet RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCmd, bool fromObj)
+{
+ const RlvCommand rlvCmd(idObj, strCmd);
+ return processCommand(std::ref(rlvCmd), fromObj);
+}
+
+ECmdRet RlvHandler::processCommand(std::reference_wrapper<const RlvCommand> rlvCmd, bool fromObj)
+{
+ {
+ const RlvCommand& rlvCmdTmp = rlvCmd; // Reference to the temporary with limited variable scope since we don't want it to leak below
+
+ RLV_DEBUGS << "[" << rlvCmdTmp.getObjectID() << "]: " << rlvCmdTmp.asString() << RLV_ENDL;
+ if (!rlvCmdTmp.isValid())
+ {
+ RLV_DEBUGS << "\t-> invalid syntax" << RLV_ENDL;
+ return ECmdRet::FailedSyntax;
+ }
+ if (rlvCmdTmp.isBlocked())
+ {
+ RLV_DEBUGS << "\t-> blocked command" << RLV_ENDL;
+ return ECmdRet::FailedDisabled;
+ }
+ }
+
+ ECmdRet eRet = ECmdRet::Unknown;
+ switch (rlvCmd.get().getParamType())
+ {
+ case EParamType::Reply:
+ eRet = rlvCmd.get().processCommand();
+ break;
+ case EParamType::Unknown:
+ default:
+ eRet = ECmdRet::FailedParam;
+ break;
+ }
+ RLV_ASSERT(ECmdRet::Unknown != eRet);
+
+ RLV_DEBUGS << "\t--> command " << (isReturnCodeSuccess(eRet) ? "succeeded" : "failed") << RLV_ENDL;
+
+ return eRet;
+}
+
+// ============================================================================
+// Initialization helper functions
+//
+
+bool RlvHandler::canEnable()
+{
+ return LLStartUp::getStartupState() <= STATE_LOGIN_CLEANUP;
+}
+
+bool RlvHandler::setEnabled(bool enable)
+{
+ if (mIsEnabled == enable)
+ return enable;
+
+ if (enable && canEnable())
+ {
+ RLV_INFOS << "Enabling Restrained Love API support - " << Strings::getVersionAbout() << RLV_ENDL;
+ mIsEnabled = true;
+ }
+
+ return mIsEnabled;
+}
+
+// ============================================================================
+// Command handlers (RLV_TYPE_REPLY)
+//
+
+ECmdRet CommandHandlerBaseImpl<EParamType::Reply>::processCommand(const RlvCommand& rlvCmd, ReplyHandlerFunc* pHandler)
+{
+ // Sanity check - <param> should specify a - valid - reply channel
+ S32 nChannel;
+ if (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel) || !Util::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgentID))
+ return ECmdRet::FailedParam;
+
+ std::string strReply;
+ ECmdRet eRet = (*pHandler)(rlvCmd, strReply);
+
+ // If we made it this far then:
+ // - the command was handled successfully so we send off the response
+ // - the command failed but we still send off an - empty - response to keep the issuing script from blocking
+ if (nChannel != 0)
+ {
+ Util::sendChatReply(nChannel, strReply);
+ }
+ RlvHandler::instance().mOnCommandOutput(rlvCmd, nChannel, strReply);
+
+ return eRet;
+}
+
+// Handles: @getcommand[:<behaviour>[;<type>[;<separator>]]]=<channel>
+template<> template<>
+ECmdRet ReplyHandler<EBehaviour::GetCommand>::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+ std::vector<std::string> optionList;
+ Util::parseStringList(rlvCmd.getOption(), optionList);
+
+ // If a second parameter is present it'll specify the command type
+ EParamType eType = EParamType::Unknown;
+ if (optionList.size() >= 2)
+ {
+ if (optionList[1] == "any" || optionList[1].empty())
+ eType = EParamType::Unknown;
+ else if (optionList[1] == "add")
+ eType = EParamType::AddRem;
+ else if (optionList[1] == "force")
+ eType = EParamType::Force;
+ else if (optionList[1] == "reply")
+ eType = EParamType::Reply;
+ else
+ return ECmdRet::FailedOption;
+ }
+
+ std::list<std::string> cmdList;
+ if (BehaviourDictionary::instance().getCommands(!optionList.empty() ? optionList[0] : LLStringUtil::null, eType, cmdList))
+ strReply = boost::algorithm::join(cmdList, optionList.size() >= 3 ? optionList[2] : Constants::OptionSeparator);
+ return ECmdRet::Succeeded;
+}
+
+// Handles: @version=<chnannel> and @versionnew=<channel>
+template<> template<>
+ECmdRet VersionReplyHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+ strReply = Strings::getVersion(EBehaviour::Version == rlvCmd.getBehaviourType());
+ return ECmdRet::Succeeded;
+}
+
+// Handles: @versionnum[:impl]=<channel>
+template<> template<>
+ECmdRet ReplyHandler<EBehaviour::VersionNum>::onCommand(const RlvCommand& rlvCmd, std::string& strReply)
+{
+ if (!rlvCmd.hasOption())
+ strReply = Strings::getVersionNum();
+ else if ("impl" == rlvCmd.getOption())
+ strReply = Strings::getVersionImplNum();
+ else
+ return ECmdRet::FailedOption;
+ return ECmdRet::Succeeded;
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h
new file mode 100644
index 0000000000..38612485b1
--- /dev/null
+++ b/indra/newview/rlvhandler.h
@@ -0,0 +1,80 @@
+/**
+ * @file rlvhandler.h
+ * @author Kitty Barnett
+ * @brief Primary command process and orchestration class
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "llchat.h"
+#include "llsingleton.h"
+
+#include "rlvhelper.h"
+
+class LLViewerObject;
+
+// ============================================================================
+// RlvHandler class
+//
+
+class RlvHandler : public LLSingleton<RlvHandler>
+{
+ template<Rlv::EParamType> friend struct Rlv::CommandHandlerBaseImpl;
+
+ LLSINGLETON_EMPTY_CTOR(RlvHandler);
+
+ /*
+ * Command processing
+ */
+public:
+ // Command processing helper functions
+ bool handleSimulatorChat(std::string& message, const LLChat& chat, const LLViewerObject* chatObj);
+ Rlv::ECmdRet processCommand(const LLUUID& idObj, const std::string& stCmd, bool fromObj);
+protected:
+ Rlv::ECmdRet processCommand(std::reference_wrapper<const RlvCommand> rlvCmdRef, bool fromObj);
+
+ /*
+ * Helper functions
+ */
+public:
+ // Initialization (deliberately static so they can safely be called in tight loops)
+ static bool canEnable();
+ static bool isEnabled() { return mIsEnabled; }
+ static bool setEnabled(bool enable);
+
+ /*
+ * Event handling
+ */
+public:
+ // The command output signal is triggered whenever a command produces channel or debug output
+ using command_output_signal_t = boost::signals2::signal<void (const RlvCommand&, S32, const std::string&)>;
+ boost::signals2::connection setCommandOutputCallback(const command_output_signal_t::slot_type& cb) { return mOnCommandOutput.connect(cb); }
+
+protected:
+ command_output_signal_t mOnCommandOutput;
+private:
+ static bool mIsEnabled;
+};
+
+// ============================================================================
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
new file mode 100644
index 0000000000..1dac297bf1
--- /dev/null
+++ b/indra/newview/rlvhelper.cpp
@@ -0,0 +1,389 @@
+/**
+ * @file rlvhelper.cpp
+ * @author Kitty Barnett
+ * @brief RLVa helper classes for internal use only
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltrans.h"
+#include "llviewercontrol.h"
+
+#include "rlvhelper.h"
+
+#include <boost/algorithm/string.hpp>
+
+using namespace Rlv;
+
+// ============================================================================
+// BehaviourDictionary
+//
+
+BehaviourDictionary::BehaviourDictionary()
+{
+ //
+ // Restrictions
+ //
+
+ //
+ // Reply-only
+ //
+ addEntry(new ReplyProcessor<EBehaviour::GetCommand>("getcommand"));
+ addEntry(new ReplyProcessor<EBehaviour::Version, VersionReplyHandler>("version"));
+ addEntry(new ReplyProcessor<EBehaviour::VersionNew, VersionReplyHandler>("versionnew"));
+ addEntry(new ReplyProcessor<EBehaviour::VersionNum>("versionnum"));
+
+ // Populate mString2InfoMap (the tuple <behaviour, type> should be unique)
+ for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList)
+ {
+ mString2InfoMap.insert(std::make_pair(std::make_pair(bhvr_info_p->getBehaviour(), static_cast<EParamType>(bhvr_info_p->getParamTypeMask())), bhvr_info_p));
+ }
+
+ // Populate m_Bhvr2InfoMap (there can be multiple entries per ERlvBehaviour)
+ for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList)
+ {
+ if ((bhvr_info_p->getParamTypeMask() & to_underlying(EParamType::AddRem)) && !bhvr_info_p->isSynonym())
+ {
+#ifdef RLV_DEBUG
+ for (const auto& itBhvr : boost::make_iterator_range(mBhvr2InfoMap.lower_bound(bhvr_info_p->getBehaviourType()), mBhvr2InfoMap.upper_bound(bhvr_info_p->getBehaviourType())))
+ {
+ RLV_ASSERT((itBhvr.first != bhvr_info_p->getBehaviourType()) || (itBhvr.second->getBehaviourFlags() != bhvr_info_p->getBehaviourFlags()));
+ }
+#endif // RLV_DEBUG
+ mBhvr2InfoMap.insert(std::pair(bhvr_info_p->getBehaviourType(), bhvr_info_p));
+ }
+ }
+}
+
+BehaviourDictionary::~BehaviourDictionary()
+{
+ for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList)
+ {
+ delete bhvr_info_p;
+ }
+ mBhvrInfoList.clear();
+}
+
+void BehaviourDictionary::addEntry(const BehaviourInfo* entry_p)
+{
+ // Filter experimental commands (if disabled)
+ static LLCachedControl<bool> sEnableExperimental(gSavedSettings, Settings::EnableExperimentalCommands);
+ if (!entry_p || (!sEnableExperimental && entry_p->isExperimental()))
+ {
+ return;
+ }
+
+ // Sanity check for duplicate entries
+#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+ std::for_each(mBhvrInfoList.begin(), mBhvrInfoList.end(),
+ [&entry_p](const BehaviourInfo* bhvr_info_p) {
+ RLV_ASSERT_DBG((bhvr_info_p->getBehaviour() != entry_p->getBehaviour()) || ((bhvr_info_p->getParamTypeMask() & entry_p->getParamTypeMask()) == 0));
+ });
+#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+
+ mBhvrInfoList.push_back(entry_p);
+}
+
+const BehaviourInfo* BehaviourDictionary::getBehaviourInfo(EBehaviour eBhvr, EParamType eParamType) const
+{
+ const BehaviourInfo* bhvr_info_p = nullptr;
+ for (auto itBhvrLower = mBhvr2InfoMap.lower_bound(eBhvr), itBhvrUpper = mBhvr2InfoMap.upper_bound(eBhvr);
+ std::find_if(itBhvrLower, itBhvrUpper, [eParamType](const auto& bhvrEntry) { return bhvrEntry.second->getParamTypeMask() == to_underlying(eParamType); }) != itBhvrUpper;
+ ++itBhvrLower)
+ {
+ if (bhvr_info_p)
+ return nullptr;
+ bhvr_info_p = itBhvrLower->second;
+ }
+ return bhvr_info_p;
+}
+
+const BehaviourInfo* BehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, EParamType eParamType, bool* is_strict_p) const
+{
+ size_t idxBhvrLastPart = strBhvr.find_last_of('_');
+ std::string strBhvrLastPart((std::string::npos != idxBhvrLastPart) && (idxBhvrLastPart < strBhvr.size()) ? strBhvr.substr(idxBhvrLastPart + 1) : LLStringUtil::null);
+
+ bool isStrict = (strBhvrLastPart.compare("sec") == 0);
+ if (is_strict_p)
+ *is_strict_p = isStrict;
+
+ auto itBhvr = mString2InfoMap.find(std::make_pair((!isStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (has_flag(eParamType, EParamType::AddRem)) ? EParamType::AddRem : eParamType));
+ if ((mString2InfoMap.end() == itBhvr) && (!isStrict) && (!strBhvrLastPart.empty()) && (EParamType::Force == eParamType))
+ {
+ // No match found but it could still be a local scope modifier
+ auto itBhvrMod = mString2InfoMap.find(std::make_pair(strBhvr.substr(0, idxBhvrLastPart), EParamType::AddRem));
+ }
+
+ return ((itBhvr != mString2InfoMap.end()) && ((!isStrict) || (itBhvr->second->hasStrict()))) ? itBhvr->second : nullptr;
+}
+
+EBehaviour BehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, EParamType eParamType, bool* pisStrict) const
+{
+ const BehaviourInfo* bhvr_info_p = getBehaviourInfo(strBhvr, eParamType, pisStrict);
+ // Filter out locally scoped modifier commands since they don't actually have a unique behaviour value of their own
+ return bhvr_info_p->getBehaviourType();
+}
+
+bool BehaviourDictionary::getCommands(const std::string& strMatch, EParamType eParamType, std::list<std::string>& cmdList) const
+{
+ cmdList.clear();
+ for (const BehaviourInfo* bhvr_info_p : mBhvrInfoList)
+ {
+ if ((bhvr_info_p->getParamTypeMask() & to_underlying(eParamType)) || (EParamType::Unknown == eParamType))
+ {
+ std::string strCmd = bhvr_info_p->getBehaviour();
+ if ((std::string::npos != strCmd.find(strMatch)) || (strMatch.empty()))
+ cmdList.push_back(strCmd);
+ if ((bhvr_info_p->hasStrict()) && ((std::string::npos != strCmd.append("_sec").find(strMatch)) || (strMatch.empty())))
+ cmdList.push_back(strCmd);
+ }
+ }
+ return !cmdList.empty();
+}
+
+bool BehaviourDictionary::getHasStrict(EBehaviour eBhvr) const
+{
+ for (const auto& itBhvr : boost::make_iterator_range(mBhvr2InfoMap.lower_bound(eBhvr), mBhvr2InfoMap.upper_bound(eBhvr)))
+ {
+ // Only restrictions can be strict
+ if (to_underlying(EParamType::AddRem) != itBhvr.second->getParamTypeMask())
+ continue;
+ return itBhvr.second->hasStrict();
+ }
+ RLV_ASSERT(false);
+ return false;
+}
+
+void BehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, EParamType eParamType, BehaviourInfo::EBehaviourFlags eBhvrFlag, bool fEnable)
+{
+ auto itBhvr = mString2InfoMap.find(std::make_pair(strBhvr, (has_flag(eParamType, EParamType::AddRem)) ? EParamType::AddRem : eParamType));
+ if (mString2InfoMap.end() != itBhvr)
+ {
+ const_cast<BehaviourInfo*>(itBhvr->second)->toggleBehaviourFlag(eBhvrFlag, fEnable);
+ }
+}
+
+// ============================================================================
+// RlvCommmand
+//
+
+RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCmd)
+ : mObjId(idObj)
+{
+ if (parseCommand(strCmd, mBehaviour, mOption, mParam))
+ {
+ if ("n" == mParam || "add" == mParam)
+ mParamType = EParamType::Add;
+ else if ("y" == mParam || "rem" == mParam)
+ mParamType = EParamType::Remove;
+ else if ("clear" == mBehaviour) // clear is the odd one out so just make it its own type
+ mParamType = EParamType::Clear;
+ else if ("force" == mParam)
+ mParamType = EParamType::Force;
+ else if (S32 nTemp; LLStringUtil::convertToS32(mParam, nTemp)) // Assume it's a reply command if we can convert <param> to an S32
+ mParamType = EParamType::Reply;
+ }
+
+ mIsValid = mParamType != EParamType::Unknown;
+ if (!mIsValid)
+ {
+ mOption.clear();
+ mParam.clear();
+ return;
+ }
+
+ mBhvrInfo = BehaviourDictionary::instance().getBehaviourInfo(mBehaviour, mParamType, &mIsStrict);
+}
+
+RlvCommand::RlvCommand(const RlvCommand& rlvCmd, EParamType eParamType)
+ : mIsValid(rlvCmd.mIsValid), mObjId(rlvCmd.mObjId), mBehaviour(rlvCmd.mBehaviour), mBhvrInfo(rlvCmd.mBhvrInfo)
+ , mParamType( (EParamType::Unknown == eParamType) ? rlvCmd.mParamType : eParamType)
+ , mIsStrict(rlvCmd.mIsStrict), mOption(rlvCmd.mOption), mParam(rlvCmd.mParam), mIsRefCounted(rlvCmd.mIsRefCounted)
+{
+}
+
+bool RlvCommand::parseCommand(const std::string& strCmd, std::string& strBhvr, std::string& strOption, std::string& strParam)
+{
+ // Format: <behaviour>[:<option>]=<param>
+ const size_t idxOption = strCmd.find(':');
+ const size_t idxParam = strCmd.find('=');
+
+ // If <behaviour> is missing it's always an improperly formatted command
+ // If there's an option, but it comes after <param> it's also invalid
+ if ( (idxOption == 0 || idxParam == 0) ||
+ (idxOption != std::string::npos && idxOption >= idxParam) )
+ {
+ return false;
+ }
+
+ strBhvr = strCmd.substr(0, std::string::npos != idxOption ? idxOption : idxParam);
+ strOption = strParam = "";
+
+ // If <param> is missing it's an improperly formatted command
+ if (idxParam == std::string::npos || idxParam + 1 == strCmd.length())
+ {
+ // Unless "<behaviour> == "clear" AND (idxOption == 0)"
+ // OR <behaviour> == "clear" AND (idxParam != 0)
+ if (strBhvr == "clear" && (!idxOption || idxParam))
+ return true;
+ return false;
+ }
+
+ if (idxOption != std::string::npos && idxOption + 1 != idxParam)
+ strOption = strCmd.substr(idxOption + 1, idxParam - idxOption - 1);
+ strParam = strCmd.substr(idxParam + 1);
+
+ return true;
+}
+
+std::string RlvCommand::asString() const
+{
+ // NOTE: @clear=<param> should be represented as clear:<param>
+ return mParamType != EParamType::Clear
+ ? getBehaviour() + (!mOption.empty() ? ":" + mOption : "")
+ : getBehaviour() + (!mParam.empty() ? ":" + mParam : "");
+}
+
+// =========================================================================
+// Various helper classes/timers/functors
+//
+
+namespace Rlv
+{
+ // ===========================================================================
+ // CommandDbgOut
+ //
+
+ void CommandDbgOut::add(std::string strCmd, ECmdRet eRet)
+ {
+ const std::string strSuffix = getReturnCodeString(eRet);
+ if (!strSuffix.empty())
+ strCmd.append(llformat(" (%s)", strSuffix.c_str()));
+ else if (mForConsole)
+ return; // Only show console feedback on successful commands when there's an informational notice
+
+ std::string& strResult = mCommandResults[isReturnCodeSuccess(eRet) ? ECmdRet::Succeeded : (ECmdRet::Retained == eRet ? ECmdRet::Retained : ECmdRet::Failed)];
+ if (!strResult.empty())
+ strResult.append(", ");
+ strResult.append(strCmd);
+ }
+
+ std::string CommandDbgOut::get() const {
+ std::ostringstream result;
+
+ if (1 == mCommandResults.size() && !mForConsole)
+ {
+ auto it = mCommandResults.begin();
+ result << " " << getDebugVerbFromReturnCode(it->first) << ": @" << it->second;
+ }
+ else if (!mCommandResults.empty())
+ {
+ auto appendResult = [&](ECmdRet eRet, const std::string& name)
+ {
+ auto it = mCommandResults.find(eRet);
+ if (it == mCommandResults.end()) return;
+ if (!mForConsole) result << "\n - ";
+ result << LLTrans::getString(name) << ": @" << it->second;
+ };
+ if (!mForConsole)
+ result << ": @" << mOrigCmd;
+ appendResult(ECmdRet::Succeeded, !mForConsole ? "RlvDebugExecuted" : "RlvConsoleExecuted");
+ appendResult(ECmdRet::Failed, !mForConsole ? "RlvDebugFailed" : "RlvConsoleFailed");
+ appendResult(ECmdRet::Retained, !mForConsole ? "RlvDebugRetained" : "RlvConsoleRetained");
+ }
+
+ return result.str();
+ }
+
+ std::string CommandDbgOut::getDebugVerbFromReturnCode(ECmdRet eRet)
+ {
+ switch (eRet)
+ {
+ case ECmdRet::Succeeded:
+ return LLTrans::getString("RlvDebugExecuted");
+ case ECmdRet::Failed:
+ return LLTrans::getString("RlvDebugFailed");
+ case ECmdRet::Retained:
+ return LLTrans::getString("RlvDebugRetained");
+ default:
+ RLV_ASSERT(false);
+ return LLStringUtil::null;
+ }
+ }
+
+ std::string CommandDbgOut::getReturnCodeString(ECmdRet eRet)
+ {
+ switch (eRet)
+ {
+ case ECmdRet::SuccessUnset:
+ return LLTrans::getString("RlvReturnCodeUnset");
+ case ECmdRet::SuccessDuplicate:
+ return LLTrans::getString("RlvReturnCodeDuplicate");
+ case ECmdRet::SuccessDelayed:
+ return LLTrans::getString("RlvReturnCodeDelayed");
+ case ECmdRet::SuccessDeprecated:
+ return LLTrans::getString("RlvReturnCodeDeprecated");
+ case ECmdRet::FailedSyntax:
+ return LLTrans::getString("RlvReturnCodeSyntax");
+ case ECmdRet::FailedOption:
+ return LLTrans::getString("RlvReturnCodeOption");
+ case ECmdRet::FailedParam:
+ return LLTrans::getString("RlvReturnCodeParam");
+ case ECmdRet::FailedLock:
+ return LLTrans::getString("RlvReturnCodeLock");
+ case ECmdRet::FailedDisabled:
+ return LLTrans::getString("RlvReturnCodeDisabled");
+ case ECmdRet::FailedUnknown:
+ return LLTrans::getString("RlvReturnCodeUnknown");
+ case ECmdRet::FailedNoSharedRoot:
+ return LLTrans::getString("RlvReturnCodeNoSharedRoot");
+ case ECmdRet::FailedDeprecated:
+ return LLTrans::getString("RlvReturnCodeDeprecatedAndDisabled");
+ case ECmdRet::FailedNoBehaviour:
+ return LLTrans::getString("RlvReturnCodeNoBehaviour");
+ case ECmdRet::FailedUnheldBehaviour:
+ return LLTrans::getString("RlvReturnCodeUnheldBehaviour");
+ case ECmdRet::FailedBlocked:
+ return LLTrans::getString("RlvReturnCodeBlocked");
+ case ECmdRet::FailedThrottled:
+ return LLTrans::getString("RlvReturnCodeThrottled");
+ case ECmdRet::FailedNoProcessor:
+ return LLTrans::getString("RlvReturnCodeNoProcessor");
+ // The following are identified by the chat verb
+ case ECmdRet::Retained:
+ case ECmdRet::Succeeded:
+ case ECmdRet::Failed:
+ return LLStringUtil::null;
+ // The following shouldn't occur
+ case ECmdRet::Unknown:
+ default:
+ RLV_ASSERT(false);
+ return LLStringUtil::null;
+ }
+ }
+
+ // ===========================================================================
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h
new file mode 100644
index 0000000000..f0ce35b816
--- /dev/null
+++ b/indra/newview/rlvhelper.h
@@ -0,0 +1,299 @@
+/**
+ * @file rlvhelper.h
+ * @author Kitty Barnett
+ * @brief RLVa helper classes for internal use only
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "rlvdefines.h"
+
+// ============================================================================
+// Forward declarations
+//
+
+class RlvCommand;
+
+// ============================================================================
+
+namespace Rlv
+{
+ // ============================================================================
+ // BehaviourInfo class - Generic behaviour descriptor (used by restrictions, reply and force commands)
+ //
+
+ class BehaviourInfo
+ {
+ public:
+ enum EBehaviourFlags : uint32_t
+ {
+ // General behaviour flags
+ Strict = 0x0001, // Behaviour has a "_sec" version
+ Synonym = 0x0002, // Behaviour is a synonym of another
+ Extended = 0x0004, // Behaviour is part of the RLVa extended command set
+ Experimental = 0x0008, // Behaviour is part of the RLVa experimental command set
+ Blocked = 0x0010, // Behaviour is blocked
+ Deprecated = 0x0020, // Behaviour is deprecated
+ MaskGeneral = 0x0FFF,
+
+ // Force-wear specific flags
+ ForceWear_WearReplace = 0x0001 << 16,
+ ForceWear_WearAdd = 0x0002 << 16,
+ ForceWear_WearRemove = 0x0004 << 16,
+ ForceWear_Node = 0x0010 << 16,
+ ForceWear_Subtree = 0x0020 << 16,
+ ForceWear_ContextNone = 0x0100 << 16,
+ ForceWear_ContextObject = 0x0200 << 16,
+ MaskForceWear = 0xFFFFu << 16
+ };
+
+ BehaviourInfo(const std::string& strBhvr, EBehaviour eBhvr, EParamType maskParamType, std::underlying_type_t<EBehaviourFlags> nBhvrFlags = 0)
+ : mBhvr(strBhvr), mBhvrType(eBhvr), mBhvrFlags(nBhvrFlags), mMaskParamType(to_underlying(maskParamType)) {}
+ virtual ~BehaviourInfo() {}
+
+ const std::string& getBehaviour() const { return mBhvr; }
+ EBehaviour getBehaviourType() const { return mBhvrType; }
+ std::underlying_type_t<EBehaviourFlags> getBehaviourFlags() const { return mBhvrFlags; }
+ std::underlying_type_t<EParamType> getParamTypeMask() const { return mMaskParamType; }
+ bool hasStrict() const { return mBhvrFlags & Strict; }
+ bool isBlocked() const { return mBhvrFlags & Blocked; }
+ bool isExperimental() const { return mBhvrFlags & Experimental; }
+ bool isExtended() const { return mBhvrFlags & Extended; }
+ bool isSynonym() const { return mBhvrFlags & Synonym; }
+ void toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable);
+
+ virtual ECmdRet processCommand(const RlvCommand& rlvCmd) const { return ECmdRet::FailedNoProcessor; }
+
+ protected:
+ std::string mBhvr;
+ EBehaviour mBhvrType;
+ std::underlying_type_t<EBehaviourFlags> mBhvrFlags;
+ std::underlying_type_t<EParamType> mMaskParamType;
+ };
+
+ inline void BehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable)
+ {
+ if (fEnable)
+ mBhvrFlags |= eBhvrFlag;
+ else
+ mBhvrFlags &= ~eBhvrFlag;
+ }
+
+ // ============================================================================
+ // BehaviourDictionary and related classes
+ //
+
+ class BehaviourDictionary : public LLSingleton<BehaviourDictionary>
+ {
+ LLSINGLETON(BehaviourDictionary);
+ protected:
+ ~BehaviourDictionary() override;
+ public:
+ void addEntry(const BehaviourInfo* entry_p);
+
+ /*
+ * General helper functions
+ */
+ public:
+ EBehaviour getBehaviourFromString(const std::string& strBhvr, EParamType eParamType, bool* is_strict_p = nullptr) const;
+ const BehaviourInfo* getBehaviourInfo(EBehaviour eBhvr, EParamType eParamType) const;
+ const BehaviourInfo* getBehaviourInfo(const std::string& strBhvr, EParamType eParamType, bool* is_strict_p = nullptr) const;
+ bool getCommands(const std::string& strMatch, EParamType eParamType, std::list<std::string>& cmdList) const;
+ bool getHasStrict(EBehaviour eBhvr) const;
+ void toggleBehaviourFlag(const std::string& strBhvr, EParamType eParamType, BehaviourInfo::EBehaviourFlags eBvhrFlag, bool fEnable);
+
+ /*
+ * Member variables
+ */
+ protected:
+ std::list<const BehaviourInfo*> mBhvrInfoList;
+ std::map<std::pair<std::string, EParamType>, const BehaviourInfo*> mString2InfoMap;
+ std::multimap<EBehaviour, const BehaviourInfo*> mBhvr2InfoMap;
+ };
+
+ // ============================================================================
+ // CommandHandler and related classes
+ //
+
+ typedef ECmdRet(BhvrHandlerFunc)(const RlvCommand&, bool&);
+ typedef void(BhvrToggleHandlerFunc)(EBehaviour, bool);
+ typedef ECmdRet(ForceHandlerFunc)(const RlvCommand&);
+ typedef ECmdRet(ReplyHandlerFunc)(const RlvCommand&, std::string&);
+
+ //
+ // CommandHandlerBaseImpl - Base implementation for each command type (the old process(AddRem|Force|Reply)Command functions)
+ //
+ template<EParamType paramType> struct CommandHandlerBaseImpl;
+ template<> struct CommandHandlerBaseImpl<EParamType::AddRem> { static ECmdRet processCommand(const RlvCommand&, BhvrHandlerFunc*, BhvrToggleHandlerFunc* = nullptr); };
+ template<> struct CommandHandlerBaseImpl<EParamType::Force> { static ECmdRet processCommand(const RlvCommand&, ForceHandlerFunc*); };
+ template<> struct CommandHandlerBaseImpl<EParamType::Reply> { static ECmdRet processCommand(const RlvCommand&, ReplyHandlerFunc*); };
+
+ //
+ // CommandHandler - The actual command handler (Note that a handler is more general than a processor; a handler can - for instance - be used by multiple processors)
+ //
+ #if LL_WINDOWS
+ #define RLV_TEMPL_FIX(x) template<x>
+ #else
+ #define RLV_TEMPL_FIX(x) template<typename Placeholder = int>
+ #endif // LL_WINDOWS
+
+
+ template <EParamType templParamType, EBehaviour templBhvr>
+ struct CommandHandler
+ {
+ RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::AddRem>::type) static ECmdRet onCommand(const RlvCommand&, bool&);
+ RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::AddRem>::type) static void onCommandToggle(EBehaviour, bool);
+ RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::Force>::type) static ECmdRet onCommand(const RlvCommand&);
+ RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::Reply>::type) static ECmdRet onCommand(const RlvCommand&, std::string&);
+ };
+
+ // Aliases to improve readability in definitions
+ template<EBehaviour templBhvr> using BehaviourHandler = CommandHandler<EParamType::AddRem, templBhvr>;
+ template<EBehaviour templBhvr> using BehaviourToggleHandler = BehaviourHandler<templBhvr>;
+ template<EBehaviour templBhvr> using ForceHandler = CommandHandler<EParamType::Force, templBhvr>;
+ template<EBehaviour templBhvr> using ReplyHandler = CommandHandler<EParamType::Reply, templBhvr>;
+
+ // List of shared handlers
+ using VersionReplyHandler = ReplyHandler<EBehaviour::Version>; // Shared between @version and @versionnew
+
+ //
+ // CommandProcessor - Templated glue class that brings BehaviourInfo, CommandHandlerBaseImpl and CommandHandler together
+ //
+ template <EParamType templParamType, EBehaviour templBhvr, typename handlerImpl = CommandHandler<templParamType, templBhvr>, typename baseImpl = CommandHandlerBaseImpl<templParamType>>
+ class CommandProcessor : public BehaviourInfo
+ {
+ public:
+ // Default constructor used by behaviour specializations
+ RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr != EBehaviour::Unknown>::type)
+ CommandProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, templBhvr, templParamType, nBhvrFlags) {}
+
+ // Constructor used when we don't want to specialize on behaviour (see BehaviourGenericProcessor)
+ RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr == EBehaviour::Unknown>::type)
+ CommandProcessor(const std::string& strBhvr, EBehaviour eBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, eBhvr, templParamType, nBhvrFlags) {}
+
+ ECmdRet processCommand(const RlvCommand& rlvCmd) const override { return baseImpl::processCommand(rlvCmd, &handlerImpl::onCommand); }
+ };
+
+ // Aliases to improve readability in definitions
+ template<EBehaviour templBhvr, typename handlerImpl = CommandHandler<EParamType::AddRem, templBhvr>> using BehaviourProcessor = CommandProcessor<EParamType::AddRem, templBhvr, handlerImpl>;
+ template<EBehaviour templBhvr, typename handlerImpl = CommandHandler<EParamType::Force, templBhvr>> using ForceProcessor = CommandProcessor<EParamType::Force, templBhvr, handlerImpl>;
+ template<EBehaviour templBhvr, typename handlerImpl = CommandHandler<EParamType::Reply, templBhvr>> using ReplyProcessor = CommandProcessor<EParamType::Reply, templBhvr, handlerImpl>;
+
+ // Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense)
+ template<EBehaviourOptionType templOptionType> struct BehaviourGenericHandler { static ECmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); };
+ template<EBehaviourOptionType templOptionType> using BehaviourGenericProcessor = BehaviourProcessor<EBehaviour::Unknown, BehaviourGenericHandler<templOptionType>>;
+ template<EBehaviourOptionType templOptionType> struct ForceGenericHandler { static ECmdRet onCommand(const RlvCommand& rlvCmd); };
+ template<EBehaviourOptionType templOptionType> using ForceGenericProcessor = ForceProcessor<EBehaviour::Unknown, ForceGenericHandler<templOptionType>>;
+
+ // ============================================================================
+ // BehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions)
+ //
+
+ template <EBehaviour eBhvr, typename handlerImpl = BehaviourHandler<eBhvr>, typename toggleHandlerImpl = BehaviourToggleHandler<eBhvr>>
+ class BehaviourToggleProcessor : public BehaviourInfo
+ {
+ public:
+ BehaviourToggleProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, eBhvr, EParamType::AddRem, nBhvrFlags) {}
+ ECmdRet processCommand(const RlvCommand& rlvCmd) const override { return CommandHandlerBaseImpl<EParamType::AddRem>::processCommand(rlvCmd, &handlerImpl::onCommand, &toggleHandlerImpl::onCommandToggle); }
+ };
+ template <EBehaviour eBhvr, EBehaviourOptionType optionType, typename toggleHandlerImpl = BehaviourToggleHandler<eBhvr>> using RlvBehaviourGenericToggleProcessor = BehaviourToggleProcessor<eBhvr, BehaviourGenericHandler<optionType>, toggleHandlerImpl>;
+
+ // ============================================================================
+ // Various helper classes/timers/functors
+ //
+
+ struct CommandDbgOut
+ {
+ CommandDbgOut(const std::string& orig_cmd, bool for_console) : mOrigCmd(orig_cmd), mForConsole(for_console) {}
+ void add(std::string strCmd, ECmdRet eRet);
+ std::string get() const;
+ static std::string getDebugVerbFromReturnCode(ECmdRet eRet);
+ static std::string getReturnCodeString(ECmdRet eRet);
+ private:
+ std::string mOrigCmd;
+ std::map<ECmdRet, std::string> mCommandResults;
+ bool mForConsole = false;
+ };
+}
+
+// ============================================================================
+// RlvCommand
+//
+
+class RlvCommand
+{
+public:
+ explicit RlvCommand(const LLUUID& idObj, const std::string& strCmd);
+ RlvCommand(const RlvCommand& rlvCmd, Rlv::EParamType eParamType = Rlv::EParamType::Unknown);
+
+ /*
+ * Member functions
+ */
+public:
+ std::string asString() const;
+ const std::string& getBehaviour() const { return mBehaviour; }
+ const Rlv::BehaviourInfo* getBehaviourInfo() const { return mBhvrInfo; }
+ Rlv::EBehaviour getBehaviourType() const { return (mBhvrInfo) ? mBhvrInfo->getBehaviourType() : Rlv::EBehaviour::Unknown; }
+ U32 getBehaviourFlags() const { return (mBhvrInfo) ? mBhvrInfo->getBehaviourFlags() : 0; }
+ const LLUUID& getObjectID() const { return mObjId; }
+ const std::string& getOption() const { return mOption; }
+ const std::string& getParam() const { return mParam; }
+ Rlv::EParamType getParamType() const { return mParamType; }
+ bool hasOption() const { return !mOption.empty(); }
+ bool isBlocked() const { return (mBhvrInfo) ? mBhvrInfo->isBlocked() : false; }
+ bool isRefCounted() const { return mIsRefCounted; }
+ bool isStrict() const { return mIsStrict; }
+ bool isValid() const { return mIsValid; }
+ Rlv::ECmdRet processCommand() const { return (mBhvrInfo) ? mBhvrInfo->processCommand(*this) : Rlv::ECmdRet::FailedNoProcessor; }
+
+protected:
+ static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam);
+ bool markRefCounted() const { return mIsRefCounted = true; }
+
+ /*
+ * Operators
+ */
+public:
+ bool operator ==(const RlvCommand&) const;
+
+ /*
+ * Member variables
+ */
+protected:
+ bool mIsValid = false;
+ LLUUID mObjId;
+ std::string mBehaviour;
+ const Rlv::BehaviourInfo* mBhvrInfo = nullptr;
+ Rlv::EParamType mParamType = Rlv::EParamType::Unknown;
+ bool mIsStrict = false;
+ std::string mOption;
+ std::string mParam;
+ mutable bool mIsRefCounted = false;
+
+ friend class RlvHandler;
+ friend class RlvObject;
+ template<Rlv::EParamType> friend struct Rlv::CommandHandlerBaseImpl;
+};
+
+// ============================================================================
diff --git a/indra/newview/scripts/lua/frame_profile.lua b/indra/newview/scripts/lua/frame_profile.lua
new file mode 100644
index 0000000000..3c6353ff68
--- /dev/null
+++ b/indra/newview/scripts/lua/frame_profile.lua
@@ -0,0 +1,24 @@
+-- Trigger Develop -> Render Tests -> Frame Profile
+
+LLAgent = require 'LLAgent'
+startup = require 'startup'
+Timer = (require 'timers').Timer
+UI = require 'UI'
+
+startup.wait('STATE_STARTED')
+
+-- teleport to http://maps.secondlife.com/secondlife/Bug%20Island/220/224/27
+print(LLAgent.teleport{regionname='Bug Island', x=220, y=224, z=27})
+Timer(10, 'wait')
+LLAgent.setCamera{camera_pos={220, 224, 26}, camera_locked=true,
+ focus_pos ={228, 232, 26}, focus_locked=true}
+Timer(1, 'wait')
+-- This freezes the viewer for perceptible realtime
+UI.popup:tip('starting Render Tests -> Frame Profile')
+UI.call("Advanced.ClickRenderProfile")
+Timer(1, 'wait')
+LLAgent.removeCamParams()
+LLAgent.setFollowCamActive(false)
+
+-- Home, James!
+print(LLAgent.teleport('home'))
diff --git a/indra/newview/scripts/lua/frame_profile_quit.lua b/indra/newview/scripts/lua/frame_profile_quit.lua
new file mode 100644
index 0000000000..ad136c86d2
--- /dev/null
+++ b/indra/newview/scripts/lua/frame_profile_quit.lua
@@ -0,0 +1,34 @@
+-- Trigger Develop -> Render Tests -> Frame Profile and quit
+
+assert(arg.n == 3, 'Usage: frame_profile_quit.lua x y z (for camera focus)')
+-- Try coercing string arguments to numbers, using Lua's implicit conversion.
+-- If the args passed as x, y, z won't convert nicely to numbers, better find
+-- out now.
+focus = {arg[1]+0, arg[2]+0, arg[3]+0}
+
+LLAgent = require 'LLAgent'
+logout = require 'logout'
+startup = require 'startup'
+Timer = (require 'timers').Timer
+UI = require 'UI'
+
+startup.wait('STATE_STARTED')
+
+-- Figure out where we are
+camera = LLAgent.getRegionPosition()
+-- assume z is the agent's feet, add 2 meters
+camera[2] += 2
+
+Timer(10, 'wait')
+LLAgent.setCamera{camera_pos=camera, camera_locked=true,
+ focus_pos=focus, focus_locked=true}
+Timer(1, 'wait')
+-- This freezes the viewer for perceptible realtime
+UI.popup:tip('starting Render Tests -> Frame Profile')
+UI.call("Advanced.ClickRenderProfile")
+Timer(1, 'wait')
+LLAgent.removeCamParams()
+LLAgent.setFollowCamActive(false)
+
+-- done
+logout()
diff --git a/indra/newview/scripts/lua/luafloater_camera_control.xml b/indra/newview/scripts/lua/luafloater_camera_control.xml
new file mode 100644
index 0000000000..0601a363e5
--- /dev/null
+++ b/indra/newview/scripts/lua/luafloater_camera_control.xml
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="350"
+ layout="topleft"
+ name="camera_demo"
+ title="Follow camera control"
+ width="360">
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="100"
+ layout="topleft"
+ top="30"
+ left="10"
+ name="camera_lbl">
+ Camera position:
+ </text>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="12"
+ left="10"
+ value="X"
+ name="cam_x_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="cam_x"
+ top_delta="-2"
+ left_pad="5"
+ width="65" />
+ <button
+ follows="left|bottom"
+ height="20"
+ image_overlay="Icon_Copy"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ tool_tip="Use Agent position"
+ name="agent_cam_btn"
+ left_pad="10"
+ width="20" >
+ </button>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="10"
+ value="Y"
+ name="cam_y_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="cam_y"
+ top_delta="-2"
+ left_pad="5"
+ width="65" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="10"
+ value="Z"
+ name="cam_z_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="cam_z"
+ top_delta="-2"
+ left_pad="5"
+ width="65" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="100"
+ layout="topleft"
+ top="30"
+ left="145"
+ name="focus_lbl">
+ Focus position:
+ </text>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="12"
+ left="145"
+ value="X"
+ name="cam_x_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="focus_x"
+ top_delta="-2"
+ left_pad="5"
+ width="60" />
+ <button
+ follows="left|bottom"
+ height="20"
+ image_overlay="Icon_Copy"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ tool_tip="Use Agent position"
+ name="agent_focus_btn"
+ left_pad="10"
+ width="20" >
+ </button>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="145"
+ value="Y"
+ name="cam_y_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="focus_y"
+ top_delta="-2"
+ left_pad="5"
+ width="60" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="10"
+ layout="topleft"
+ top_pad="7"
+ left="145"
+ value="Z"
+ name="cam_z_lbl"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="focus_z"
+ top_delta="-2"
+ left_pad="5"
+ width="60" />
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ width="100"
+ layout="topleft"
+ top="30"
+ left="270"
+ name="focus_lbl">
+ Lock:
+ </text>
+ <check_box
+ width="80"
+ height="21"
+ layout="topleft"
+ follows="top|left"
+ top_pad="12"
+ label="Camera"
+ name="lock_camera_ctrl"/>
+ <check_box
+ width="80"
+ height="21"
+ layout="topleft"
+ follows="top|left"
+ top_pad="2"
+ label="Focus"
+ name="lock_focus_ctrl"/>
+ <button
+ follows="left|bottom"
+ height="25"
+ label="Update params"
+ layout="topleft"
+ name="update_btn"
+ left="10"
+ top="140"
+ width="120" >
+ </button>
+ <button
+ follows="left|bottom"
+ height="25"
+ label="Reset"
+ layout="topleft"
+ name="reset_btn"
+ left_pad="15"
+ width="90" >
+ </button>
+ <text_editor
+ follows="top|left"
+ font="SansSerif"
+ height="160"
+ left="5"
+ enabled="false"
+ name="events_editor"
+ top_pad="15"
+ word_wrap="true"
+ max_length="65536"
+ width="350"/>
+</floater>
diff --git a/indra/newview/scripts/lua/luafloater_demo.xml b/indra/newview/scripts/lua/luafloater_demo.xml
new file mode 100644
index 0000000000..b2273d7718
--- /dev/null
+++ b/indra/newview/scripts/lua/luafloater_demo.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="300"
+ layout="topleft"
+ name="lua_demo"
+ title="LUA"
+ width="320">
+ <check_box
+ height="16"
+ label="Disable button"
+ layout="topleft"
+ top_pad="35"
+ left="5"
+ name="disable_ctrl"
+ width="146" />
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ max_length_bytes="50"
+ name="openfloater_cmd"
+ top_delta="25"
+ width="100" />
+ <button
+ follows="left|bottom"
+ height="23"
+ label="Open floater"
+ layout="topleft"
+ name="open_btn"
+ top_delta="25"
+ width="100" >
+ </button>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ top="30"
+ left_delta="170"
+ name="title_lbl">
+ Select title
+ </text>
+ <combo_box
+ follows="top|left"
+ height="23"
+ name="title_cmb"
+ top_pad="5"
+ width="100">
+ <combo_box.item
+ label="LUA"
+ value="LUA" />
+ <combo_box.item
+ label="LUA floater"
+ value="LUA floater" />
+ <combo_box.item
+ label="LUA-U title"
+ value="LUA-U title" />
+ </combo_box>
+ <text
+ type="string"
+ follows="left|bottom"
+ height="10"
+ layout="topleft"
+ top_delta="50"
+ name="show_time_lbl">
+ Double click me
+ </text>
+ <text
+ type="string"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ top_pad="15"
+ font="SansSerif"
+ text_color="white"
+ left_delta="15"
+ name="time_lbl"/>
+ <text_editor
+ follows="top|left"
+ font="SansSerif"
+ height="140"
+ left="5"
+ enabled="false"
+ name="events_editor"
+ top_pad="15"
+ word_wrap="true"
+ max_length="65536"
+ width="310"/>
+</floater>
diff --git a/indra/newview/scripts/lua/luafloater_gesture_list.xml b/indra/newview/scripts/lua/luafloater_gesture_list.xml
new file mode 100644
index 0000000000..a38a04eed0
--- /dev/null
+++ b/indra/newview/scripts/lua/luafloater_gesture_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="150"
+ layout="topleft"
+ name="lua_gestures"
+ title="Gestures"
+ width="320">
+ <scroll_list
+ draw_heading="false"
+ left="5"
+ width="310"
+ height="115"
+ top_pad ="25"
+ follows="all"
+ name="gesture_list">
+ <scroll_list.columns
+ name="gesture_name"
+ label="Name"/>
+ </scroll_list>
+</floater>
diff --git a/indra/newview/scripts/lua/luafloater_outfits_list.xml b/indra/newview/scripts/lua/luafloater_outfits_list.xml
new file mode 100644
index 0000000000..8cab864308
--- /dev/null
+++ b/indra/newview/scripts/lua/luafloater_outfits_list.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="205"
+ layout="topleft"
+ name="lua_outfits"
+ title="Outfits"
+ width="325">
+ <scroll_list
+ draw_heading="false"
+ left="5"
+ width="315"
+ height="150"
+ top_pad ="25"
+ follows="all"
+ name="outfits_list">
+ <scroll_list.columns
+ name="outfit_name"
+ label="Name"/>
+ </scroll_list>
+ <button
+ follows="left|bottom"
+ height="23"
+ label="Replace COF"
+ layout="topleft"
+ name="replace_btn"
+ enabled="false"
+ top_pad="5"
+ width="95" >
+ </button>
+ <button
+ follows="left|bottom"
+ height="23"
+ label="Add to COF"
+ left_pad="7"
+ layout="topleft"
+ name="add_btn"
+ enabled="false"
+ width="95" >
+ </button>
+ <button
+ follows="left|bottom"
+ height="23"
+ label="Show wearables"
+ left_pad="7"
+ layout="topleft"
+ name="select_btn"
+ enabled="false"
+ width="111" >
+ </button>
+</floater>
diff --git a/indra/newview/scripts/lua/luafloater_speedometer.xml b/indra/newview/scripts/lua/luafloater_speedometer.xml
new file mode 100644
index 0000000000..54b99c7d48
--- /dev/null
+++ b/indra/newview/scripts/lua/luafloater_speedometer.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="60"
+ layout="topleft"
+ name="lua_speedometer"
+ title="Speedometer"
+ can_minimize="false"
+ width="170">
+ <text
+ type="string"
+ follows="left|top"
+ font="SansSerifBold"
+ font.size="Huge"
+ text_color="White"
+ layout="topleft"
+ top="25"
+ left_delta="30"
+ width="70"
+ height="30"
+ name="speed_lbl"/>
+ <text
+ type="string"
+ follows="left|top"
+ width="55"
+ height="30"
+ font="SansSerifBold"
+ font.size="Huge"
+ text_color="White"
+ layout="topleft"
+ left_pad="2"
+ name="mps_lbl">
+ m/s
+ </text>
+</floater>
diff --git a/indra/newview/scripts/lua/qtest.lua b/indra/newview/scripts/lua/qtest.lua
new file mode 100644
index 0000000000..9526f58b04
--- /dev/null
+++ b/indra/newview/scripts/lua/qtest.lua
@@ -0,0 +1,146 @@
+-- Exercise the Queue, WaitQueue, ErrorQueue family
+
+Queue = require('Queue')
+WaitQueue = require('WaitQueue')
+ErrorQueue = require('ErrorQueue')
+util = require('util')
+
+inspect = require('inspect')
+
+-- resume() wrapper to propagate errors
+function resume(co, ...)
+ -- if there's an idiom other than table.pack() to assign an arbitrary
+ -- number of return values, I don't yet know it
+ local ok_result = table.pack(coroutine.resume(co, ...))
+ if not ok_result[1] then
+ -- if [1] is false, then [2] is the error message
+ error(ok_result[2])
+ end
+ -- ok is true, whew, just return the rest of the values
+ return table.unpack(ok_result, 2)
+end
+
+-- ------------------ Queue variables are instance-specific ------------------
+q1 = Queue()
+q2 = Queue()
+
+q1:Enqueue(17)
+
+assert(not q1:IsEmpty())
+assert(q2:IsEmpty())
+assert(q1:Dequeue() == 17)
+assert(q1:Dequeue() == nil)
+assert(q2:Dequeue() == nil)
+
+-- ----------------------------- test WaitQueue ------------------------------
+q1 = WaitQueue()
+q2 = WaitQueue()
+result = {}
+values = { 1, 1, 2, 3, 5, 8, 13, 21 }
+
+for i, value in pairs(values) do
+ q1:Enqueue(value)
+end
+-- close() while not empty tests that queue drains before reporting done
+q1:close()
+
+-- ensure that WaitQueue instance variables are in fact independent
+assert(q2:IsEmpty())
+
+-- consumer() coroutine to pull from the passed q until closed
+function consumer(desc, q)
+ print(string.format('consumer(%s) start', desc))
+ local value = q:Dequeue()
+ while value ~= nil do
+ print(string.format('consumer(%s) got %q', desc, value))
+ table.insert(result, value)
+ value = q:Dequeue()
+ end
+ print(string.format('consumer(%s) done', desc))
+end
+
+-- run two consumers
+coa = coroutine.create(consumer)
+cob = coroutine.create(consumer)
+-- Since consumer() doesn't yield while it can still retrieve values,
+-- consumer(a) will dequeue all values from q1 and return when done.
+resume(coa, 'a', q1)
+-- consumer(b) will wake up to find the queue empty and closed.
+resume(cob, 'b', q1)
+coroutine.close(coa)
+coroutine.close(cob)
+
+print('values:', inspect(values))
+print('result:', inspect(result))
+
+assert(util.equal(values, result))
+
+-- try incrementally enqueueing values
+q3 = WaitQueue()
+result = {}
+values = { 'This', 'is', 'a', 'test', 'script' }
+
+coros = {}
+for _, name in {'a', 'b'} do
+ local coro = coroutine.create(consumer)
+ table.insert(coros, coro)
+ -- Resuming both coroutines should leave them both waiting for a queue item.
+ resume(coro, name, q3)
+end
+
+for _, s in pairs(values) do
+ print(string.format('Enqueue(%q)', s))
+ q3:Enqueue(s)
+end
+q3:close()
+
+function joinall(coros)
+ local running
+ local errors = 0
+ repeat
+ running = false
+ for i, coro in pairs(coros) do
+ if coroutine.status(coro) == 'suspended' then
+ running = true
+ -- directly call coroutine.resume() instead of our resume()
+ -- wrapper because we explicitly check for errors here
+ local ok, message = coroutine.resume(coro)
+ if not ok then
+ print('*** ' .. message)
+ errors += 1
+ end
+ if coroutine.status(coro) == 'dead' then
+ coros[i] = nil
+ end
+ end
+ end
+ until not running
+ return errors
+end
+
+joinall(coros)
+
+print(string.format('%q', table.concat(result, ' ')))
+assert(util.equal(values, result))
+
+-- ----------------------------- test ErrorQueue -----------------------------
+q4 = ErrorQueue()
+result = {}
+values = { 'This', 'is', 'a', 'test', 'script' }
+
+coros = {}
+for _, name in {'a', 'b'} do
+ local coro = coroutine.create(consumer)
+ table.insert(coros, coro)
+ -- Resuming both coroutines should leave them both waiting for a queue item.
+ resume(coro, name, q4)
+end
+
+for i = 1, 4 do
+ print(string.format('Enqueue(%q)', values[i]))
+ q4:Enqueue(values[i])
+end
+q4:Error('something went wrong')
+
+assert(joinall(coros) == 2)
+
diff --git a/indra/newview/scripts/lua/require/ErrorQueue.lua b/indra/newview/scripts/lua/require/ErrorQueue.lua
new file mode 100644
index 0000000000..e6e9a5ef48
--- /dev/null
+++ b/indra/newview/scripts/lua/require/ErrorQueue.lua
@@ -0,0 +1,37 @@
+-- ErrorQueue isa WaitQueue with the added feature that a producer can push an
+-- error through the queue. Once that error is dequeued, every consumer will
+-- raise that error.
+
+local WaitQueue = require('WaitQueue')
+local function dbg(...) end
+-- local dbg = require('printf')
+local util = require('util')
+
+local ErrorQueue = WaitQueue()
+
+util.classctor(ErrorQueue)
+
+function ErrorQueue:Error(message)
+ -- Setting Error() is a marker, like closing the queue. Once we reach the
+ -- error, every subsequent Dequeue() call will raise the same error.
+ dbg('Setting self._closed to %q', message)
+ self._closed = message
+ self:_wake_waiters()
+end
+
+function ErrorQueue:Dequeue()
+ local value = WaitQueue.Dequeue(self)
+ dbg('ErrorQueue:Dequeue: base Dequeue() got %s', value)
+ if value ~= nil then
+ -- queue not yet closed, show caller
+ return value
+ end
+ if self._closed == true then
+ -- WaitQueue:close() sets true: queue has only been closed, tell caller
+ return nil
+ end
+ -- self._closed is a message set by Error()
+ error(self._closed)
+end
+
+return ErrorQueue
diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua
new file mode 100644
index 0000000000..6068a916ed
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLAgent.lua
@@ -0,0 +1,188 @@
+local leap = require 'leap'
+local mapargs = require 'mapargs'
+local result_view = require 'result_view'
+
+local function result(keys)
+ local result_table = {
+ result=result_view(keys.result),
+ -- call result_table:close() to release result sets before garbage
+ -- collection or script completion
+ close = function(self)
+ result_view.close(keys.result[1])
+ end
+ }
+ -- When the result_table is destroyed, close its result_views.
+ return LL.setdtor('LLAgent result', result_table, result_table.close)
+end
+
+local LLAgent = {}
+
+function LLAgent.getID()
+ return leap.request('LLAgent', {op = 'getID'}).id
+end
+
+function LLAgent.getRegionPosition()
+ return leap.request('LLAgent', {op = 'getPosition'}).region
+end
+
+function LLAgent.getGlobalPosition()
+ return leap.request('LLAgent', {op = 'getPosition'}).global
+end
+
+-- Return array information about the agent's groups
+-- id: group id\n"
+-- name: group name\n"
+-- insignia: group insignia texture id
+-- notices: bool indicating if this user accepts notices from this group
+-- display: bool indicating if this group is listed in the user's profile
+-- contrib: user's land contribution to this group
+function LLAgent.getGroups()
+ return leap.request('LLAgent', {op = 'getGroups'}).groups
+end
+
+-- Use LL.leaphelp('LLAgent') and see 'setCameraParams' to get more info about params
+-- -- TYPE -- DEFAULT -- RANGE
+-- LLAgent.setCamera{ [, camera_pos] -- vector3
+-- [, focus_pos] -- vector3
+-- [, focus_offset] -- vector3 -- {1,0,0} -- {-10,-10,-10} to {10,10,10}
+-- [, distance] -- float (meters) -- 3 -- 0.5 to 50
+-- [, focus_threshold] -- float (meters) -- 1 -- 0 to 4
+-- [, camera_threshold] -- float (meters) -- 1 -- 0 to 4
+-- [, focus_lag] -- float (seconds) -- 0.1 -- 0 to 3
+-- [, camera_lag] -- float (seconds) -- 0.1 -- 0 to 3
+-- [, camera_pitch] -- float (degrees) -- 0 -- -45 to 80
+-- [, behindness_angle] -- float (degrees) -- 10 -- 0 to 180
+-- [, behindness_lag] -- float (seconds) -- 0 -- 0 to 3
+-- [, camera_locked] -- bool -- false
+-- [, focus_locked]} -- bool -- false
+function LLAgent.setCamera(...)
+ local args = mapargs('camera_pos,focus_pos,focus_offset,focus_lag,camera_lag,' ..
+ 'distance,focus_threshold,camera_threshold,camera_pitch,' ..
+ 'camera_locked,focus_locked,behindness_angle,behindness_lag', ...)
+ args.op = 'setCameraParams'
+ leap.send('LLAgent', args)
+end
+
+function LLAgent.setFollowCamActive(active)
+ leap.send('LLAgent', {op = 'setFollowCamActive', active = active})
+end
+
+function LLAgent.removeCamParams()
+ leap.send('LLAgent', {op = 'removeCameraParams'})
+end
+
+-- Play specified animation by "item_id" locally
+-- if "inworld" is specified as true, animation will be played inworld instead
+function LLAgent.playAnimation(...)
+ local args = mapargs('item_id,inworld', ...)
+ args.op = 'playAnimation'
+ return leap.request('LLAgent', args)
+end
+
+function LLAgent.stopAnimation(item_id)
+ return leap.request('LLAgent', {op = 'stopAnimation', item_id=item_id})
+end
+
+-- Get animation info by "item_id"
+-- reply contains "duration", "is_loop", "num_joints", "asset_id", "priority"
+function LLAgent.getAnimationInfo(item_id)
+ return leap.request('LLAgent', {op = 'getAnimationInfo', item_id=item_id}).anim_info
+end
+
+-- Teleport to specified "regionname" at specified region-relative "x", "y", "z".
+-- If "regionname" is "home", ignore "x", "y", "z" and teleport home.
+-- If "regionname" omitted, teleport to GLOBAL coordinates "x", "y", "z".
+function LLAgent.teleport(...)
+ local args = mapargs('regionname,x,y,z', ...)
+ args.op = 'teleport'
+ return leap.request('LLTeleportHandler', args).message
+end
+
+-- Call with no arguments to sit on the ground.
+-- Otherwise specify "obj_uuid" to sit on,
+-- or region "position" {x, y, z} where to find closest object to sit on.
+-- For example: LLAgent.requestSit{position=LLAgent.getRegionPosition()}
+-- Your avatar should be close enough to the object you want to sit on
+function LLAgent.requestSit(...)
+ local args = mapargs('obj_uuid,position', ...)
+ args.op = 'requestSit'
+ return leap.request('LLAgent', args)
+end
+
+function LLAgent.requestStand()
+ leap.send('LLAgent', {op = 'requestStand'})
+end
+
+-- Get the nearby avatars in a range of provided "dist",
+-- if "dist" is not specified, "RenderFarClip" setting is used
+-- reply will contain "result" table with following fields:
+-- "id", "global_pos", "region_pos", "name", "region_id"
+function LLAgent.getNearbyAvatarsList(...)
+ local args = mapargs('dist', ...)
+ args.op = 'getNearbyAvatarsList'
+ return result(leap.request('LLAgent', args))
+end
+
+-- reply will contain "result" table with following fields:
+-- "id", "global_pos", "region_pos", "region_id"
+function LLAgent.getNearbyObjectsList(...)
+ local args = mapargs('dist', ...)
+ args.op = 'getNearbyObjectsList'
+ return result(leap.request('LLAgent', args))
+end
+
+-- Get screen position of your own avatar or any other (if "avatar_id" is specified)
+-- reply contains "x", "y" coordinates and "onscreen" flag to indicate if it's actually in within the current window
+-- avatar render position is used as the point
+function LLAgent.getAgentScreenPos(...)
+ local args = mapargs('avatar_id', ...)
+ args.op = 'getAgentScreenPos'
+ return leap.request('LLAgent', args)
+end
+
+-- ***************************************************************************
+-- Autopilot
+-- ***************************************************************************
+LLAgent.autoPilotPump = "LLAutopilot"
+
+-- Start the autopilot to move to "target_global" location using specified parameters
+-- LLAgent.startAutoPilot{ target_global array of target global {x, y, z} position
+-- [, allow_flying] allow flying during autopilot [default: true]
+-- [, stop_distance] target maximum distance from target [default: autopilot guess]
+-- [, behavior_name] name of the autopilot behavior [default: (script name)]
+-- [, target_rotation] array of [x, y, z, w] quaternion values [default: no target]
+-- [, rotation_threshold] target maximum angle from target facing rotation [default: 0.03 radians]
+-- an event with "success" flag is sent to "LLAutopilot" event pump, when auto pilot is terminated
+function LLAgent.startAutoPilot(...)
+ local args = mapargs('target_global,allow_flying,stop_distance,behavior_name,target_rotation,rotation_threshold', ...)
+ args.op = 'startAutoPilot'
+ leap.send('LLAgent', args)
+end
+
+-- Update target location for currently running autopilot
+function LLAgent.setAutoPilotTarget(target_global)
+ leap.send('LLAgent', {op = 'setAutoPilotTarget', target_global=target_global})
+end
+
+-- Start the autopilot to move to the specified target location
+-- either "leader_id" (uuid of target) or "avatar_name" (avatar full name: use just first name for 'Resident') should be specified
+-- "allow_flying" [default: true], "stop_distance" [default: autopilot guess]
+function LLAgent.startFollowPilot(...)
+ local args = mapargs('leader_id,avatar_name,allow_flying,stop_distance', ...)
+ args.op = 'startFollowPilot'
+ return leap.request('LLAgent', args)
+end
+
+-- Stop the autopilot system: "user_cancel" indicates whether or not to act as though user canceled autopilot [default: false]
+function LLAgent.stopAutoPilot(...)
+ local args = mapargs('user_cancel', ...)
+ args.op = 'stopAutoPilot'
+ leap.send('LLAgent', args)
+end
+
+-- Get information about current state of the autopilot
+function LLAgent.getAutoPilot()
+ return leap.request('LLAgent', {op = 'getAutoPilot'})
+end
+
+return LLAgent
diff --git a/indra/newview/scripts/lua/require/LLAppearance.lua b/indra/newview/scripts/lua/require/LLAppearance.lua
new file mode 100644
index 0000000000..f533d22daf
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLAppearance.lua
@@ -0,0 +1,31 @@
+local leap = require 'leap'
+
+local LLAppearance = {}
+
+function LLAppearance.wearOutfit(folder, action)
+ action = action or 'add'
+ leap.request('LLAppearance', {op='wearOutfit', append = (action == 'add'), folder_id=folder})
+end
+
+function LLAppearance.wearOutfitByName(folder, action)
+ action = action or 'add'
+ leap.request('LLAppearance', {op='wearOutfit', append = (action == 'add'), folder_name=folder})
+end
+
+function LLAppearance.wearItems(items_id, replace)
+ leap.send('LLAppearance', {op='wearItems', replace = replace, items_id=items_id})
+end
+
+function LLAppearance.detachItems(items_id)
+ leap.send('LLAppearance', {op='detachItems', items_id=items_id})
+end
+
+function LLAppearance.getOutfitsList()
+ return leap.request('LLAppearance', {op='getOutfitsList'})['outfits']
+end
+
+function LLAppearance.getOutfitItems(id)
+ return leap.request('LLAppearance', {op='getOutfitItems', outfit_id = id})['items']
+end
+
+return LLAppearance
diff --git a/indra/newview/scripts/lua/require/LLChat.lua b/indra/newview/scripts/lua/require/LLChat.lua
new file mode 100644
index 0000000000..3ac3bab746
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLChat.lua
@@ -0,0 +1,39 @@
+local leap = require 'leap'
+
+local LLChat = {}
+
+-- ***************************************************************************
+-- Nearby chat
+-- ***************************************************************************
+LLChat.nearbyChatPump = "LLNearbyChat"
+
+-- 0 is public nearby channel, other channels are used to communicate with LSL scripts
+function LLChat.sendNearby(msg, channel)
+ leap.send('LLChatBar', {op='sendChat', message=msg, channel=channel})
+end
+
+function LLChat.sendWhisper(msg)
+ leap.send('LLChatBar', {op='sendChat', type='whisper', message=msg})
+end
+
+function LLChat.sendShout(msg)
+ leap.send('LLChatBar', {op='sendChat', type='shout', message=msg})
+end
+
+-- ***************************************************************************
+-- Group chat
+-- ***************************************************************************
+
+function LLChat.startGroupChat(group_id)
+ return leap.request('GroupChat', {op='startGroupChat', group_id=group_id})
+end
+
+function LLChat.leaveGroupChat(group_id)
+ leap.send('GroupChat', {op='leaveGroupChat', group_id=group_id})
+end
+
+function LLChat.sendGroupIM(msg, group_id)
+ leap.send('GroupChat', {op='sendGroupIM', message=msg, group_id=group_id})
+end
+
+return LLChat
diff --git a/indra/newview/scripts/lua/require/LLDebugSettings.lua b/indra/newview/scripts/lua/require/LLDebugSettings.lua
new file mode 100644
index 0000000000..cff1a63c21
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLDebugSettings.lua
@@ -0,0 +1,17 @@
+local leap = require 'leap'
+
+local LLDebugSettings = {}
+
+function LLDebugSettings.set(name, value)
+ leap.request('LLViewerControl', {op='set', group='Global', key=name, value=value})
+end
+
+function LLDebugSettings.toggle(name)
+ leap.request('LLViewerControl', {op='toggle', group='Global', key=name})
+end
+
+function LLDebugSettings.get(name)
+ return leap.request('LLViewerControl', {op='get', group='Global', key=name})['value']
+end
+
+return LLDebugSettings
diff --git a/indra/newview/scripts/lua/require/LLFloaterAbout.lua b/indra/newview/scripts/lua/require/LLFloaterAbout.lua
new file mode 100644
index 0000000000..a6e42d364f
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLFloaterAbout.lua
@@ -0,0 +1,11 @@
+-- Engage the LLFloaterAbout LLEventAPI
+
+local leap = require 'leap'
+
+local LLFloaterAbout = {}
+
+function LLFloaterAbout.getInfo()
+ return leap.request('LLFloaterAbout', {op='getInfo'})
+end
+
+return LLFloaterAbout
diff --git a/indra/newview/scripts/lua/require/LLGesture.lua b/indra/newview/scripts/lua/require/LLGesture.lua
new file mode 100644
index 0000000000..343b611e2c
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLGesture.lua
@@ -0,0 +1,23 @@
+-- Engage the LLGesture LLEventAPI
+
+local leap = require 'leap'
+
+local LLGesture = {}
+
+function LLGesture.getActiveGestures()
+ return leap.request('LLGesture', {op='getActiveGestures'})['gestures']
+end
+
+function LLGesture.isGesturePlaying(id)
+ return leap.request('LLGesture', {op='isGesturePlaying', id=id})['playing']
+end
+
+function LLGesture.startGesture(id)
+ leap.send('LLGesture', {op='startGesture', id=id})
+end
+
+function LLGesture.stopGesture(id)
+ leap.send('LLGesture', {op='stopGesture', id=id})
+end
+
+return LLGesture
diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua
new file mode 100644
index 0000000000..2c80a8602b
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLInventory.lua
@@ -0,0 +1,67 @@
+local leap = require 'leap'
+local mapargs = require 'mapargs'
+local result_view = require 'result_view'
+
+local function result(keys)
+ -- capture result_view() instances for both categories and items
+ local result_table = {
+ categories=result_view(keys.categories),
+ items=result_view(keys.items),
+ -- call result_table:close() to release result sets before garbage
+ -- collection or script completion
+ close = function(self)
+ result_view.close(keys.categories[1], keys.items[1])
+ end
+ }
+ -- When the result_table is destroyed, close its result_views.
+ return LL.setdtor('LLInventory result', result_table, result_table.close)
+end
+
+local LLInventory = {}
+
+-- Get the items/folders info by provided IDs,
+-- reply will contain "items" and "categories" tables accordingly
+function LLInventory.getItemsInfo(item_ids)
+ return result(leap.request('LLInventory', {op = 'getItemsInfo', item_ids=item_ids}))
+end
+
+-- Get the table of folder type names, which can be later used to get the ID of the basic folders
+function LLInventory.getFolderTypeNames()
+ return leap.request('LLInventory', {op = 'getFolderTypeNames'}).names
+end
+
+-- Get the UUID of the basic folder("Textures", "My outfits", "Sounds" etc.) by specified folder type name
+function LLInventory.getBasicFolderID(ft_name)
+ return leap.request('LLInventory', {op = 'getBasicFolderID', ft_name=ft_name}).id
+end
+
+-- Get the table of asset type names, which can be later used to get the specific items via LLInventory.collectDescendantsIf(...)
+function LLInventory.getAssetTypeNames()
+ return leap.request('LLInventory', {op = 'getAssetTypeNames'}).names
+end
+
+-- Get the direct descendants of the 'folder_id' provided,
+-- reply will contain "items" and "categories" tables accordingly
+function LLInventory.getDirectDescendants(folder_id)
+ return result(leap.request('LLInventory', {op = 'getDirectDescendants', folder_id=folder_id}))
+end
+-- backwards compatibility
+LLInventory.getDirectDescendents = LLInventory.getDirectDescendants
+
+-- Get the descendants of the 'folder_id' provided, which pass specified filters
+-- reply will contain "items" and "categories" tables accordingly
+-- LLInventory.collectDescendantsIf{ folder_id -- parent folder ID
+-- [, name] -- name (substring)
+-- [, desc] -- description (substring)
+-- [, type] -- asset type
+-- [, limit] -- item count limit in reply, maximum and default is 100
+-- [, filter_links]} -- EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)
+function LLInventory.collectDescendantsIf(...)
+ local args = mapargs('folder_id,name,desc,type,filter_links,limit', ...)
+ args.op = 'collectDescendantsIf'
+ return result(leap.request('LLInventory', args))
+end
+-- backwards compatibility
+LLInventory.collectDescendentsIf = LLInventory.collectDescendantsIf
+
+return LLInventory
diff --git a/indra/newview/scripts/lua/require/LLListener.lua b/indra/newview/scripts/lua/require/LLListener.lua
new file mode 100644
index 0000000000..b05f966097
--- /dev/null
+++ b/indra/newview/scripts/lua/require/LLListener.lua
@@ -0,0 +1,50 @@
+local fiber = require 'fiber'
+local inspect = require 'inspect'
+local leap = require 'leap'
+local util = require 'util'
+
+local LLListener = {}
+local waitfor = {}
+local listener_name = {}
+
+function LLListener:new(pump_name)
+ local obj = setmetatable({}, self)
+ self.__index = self
+ obj.name = 'Listener:' .. pump_name
+ obj._pump = pump_name
+
+ return obj
+end
+
+util.classctor(LLListener)
+
+function LLListener:handleMessages(event_data)
+ print(inspect(event_data))
+ return true
+end
+
+function LLListener:start()
+ _pump = self._pump
+ waitfor = leap.WaitFor(-1, self.name)
+ function waitfor:filter(pump, data)
+ if _pump == pump then
+ return data
+ end
+ end
+
+ fiber.launch(self.name, function()
+ event = waitfor:wait()
+ while event and self:handleMessages(event) do
+ event = waitfor:wait()
+ end
+ end)
+
+ listener_name = leap.request(leap.cmdpump(), {op='listen', source=_pump, listener="LLListener", tweak=true}).listener
+end
+
+function LLListener:stop()
+ leap.send(leap.cmdpump(), {op='stoplistening', source=self._pump, listener=listener_name})
+ waitfor:close()
+end
+
+return LLListener
diff --git a/indra/newview/scripts/lua/require/Queue.lua b/indra/newview/scripts/lua/require/Queue.lua
new file mode 100644
index 0000000000..5bc72e4057
--- /dev/null
+++ b/indra/newview/scripts/lua/require/Queue.lua
@@ -0,0 +1,51 @@
+-- from https://create.roblox.com/docs/luau/queues#implementing-queues,
+-- amended per https://www.lua.org/pil/16.1.html
+
+-- While coding some scripting in Lua
+-- I found that I needed a queua
+-- I thought of linked list
+-- But had to resist
+-- For fear it might be too obscua.
+
+local util = require 'util'
+
+local Queue = {}
+
+function Queue:new()
+ local obj = setmetatable({}, self)
+ self.__index = self
+
+ obj._first = 0
+ obj._last = -1
+ obj._queue = {}
+
+ return obj
+end
+
+util.classctor(Queue)
+
+-- Check if the queue is empty
+function Queue:IsEmpty()
+ return self._first > self._last
+end
+
+-- Add a value to the queue
+function Queue:Enqueue(value)
+ local last = self._last + 1
+ self._last = last
+ self._queue[last] = value
+end
+
+-- Remove a value from the queue
+function Queue:Dequeue()
+ if self:IsEmpty() then
+ return nil
+ end
+ local first = self._first
+ local value = self._queue[first]
+ self._queue[first] = nil
+ self._first = first + 1
+ return value
+end
+
+return Queue
diff --git a/indra/newview/scripts/lua/require/Region.lua b/indra/newview/scripts/lua/require/Region.lua
new file mode 100644
index 0000000000..e4eefece33
--- /dev/null
+++ b/indra/newview/scripts/lua/require/Region.lua
@@ -0,0 +1,17 @@
+LLFloaterAbout = require 'LLFloaterAbout'
+
+local Region = {}
+
+function Region.getInfo()
+ info = LLFloaterAbout.getInfo()
+ return {
+ HOSTNAME=info.HOSTNAME,
+ POSITION=info.POSITION,
+ POSITION_LOCAL=info.POSITION_LOCAL,
+ REGION=info.REGION,
+ SERVER_VERSION=info.SERVER_VERSION,
+ SLURL=info.SLURL,
+ }
+end
+
+return Region
diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua
new file mode 100644
index 0000000000..34f3fb75eb
--- /dev/null
+++ b/indra/newview/scripts/lua/require/UI.lua
@@ -0,0 +1,245 @@
+-- Engage the viewer's UI
+
+local leap = require 'leap'
+local mapargs = require 'mapargs'
+local result_view = require 'result_view'
+local Timer = (require 'timers').Timer
+local util = require 'util'
+
+-- Allow lazily accessing UI submodules on demand, e.g. a reference to
+-- UI.Floater lazily loads the UI/Floater module.
+local UI = util.submoduledir({}, 'UI')
+
+-- ***************************************************************************
+-- registered menu actions
+-- ***************************************************************************
+function UI.call(func, parameter)
+ -- 'call' is fire-and-forget
+ leap.request('UI', {op='call', ['function']=func, parameter=parameter})
+end
+
+function UI.callables()
+ return leap.request('UI', {op='callables'}).callables
+end
+
+function UI.getValue(path)
+ return leap.request('UI', {op='getValue', path=path})['value']
+end
+
+-- ***************************************************************************
+-- UI views
+-- ***************************************************************************
+-- Either:
+-- wreq{op='Something', a=1, b=2, ...}
+-- or:
+-- (args should be local, as this wreq() call modifies it)
+-- local args = {a=1, b=2, ...}
+-- wreq('Something', args)
+local function wreq(op_or_data, data_if_op)
+ if data_if_op ~= nil then
+ -- this is the wreq(op, data) form
+ data_if_op.op = op_or_data
+ op_or_data = data_if_op
+ end
+ return leap.request('LLWindow', op_or_data)
+end
+
+-- omit 'parent' to list all view paths
+function UI.listviews(parent)
+ return wreq{op='getPaths', under=parent}
+end
+
+function UI.viewinfo(path)
+ return wreq{op='getInfo', path=path}
+end
+
+-- ***************************************************************************
+-- mouse actions
+-- ***************************************************************************
+-- pass a table:
+-- UI.click{path=path
+-- [, button='LEFT' | 'CENTER' | 'RIGHT']
+-- [, x=x, y=y]
+-- [, hold=duration]}
+function UI.click(...)
+ local args = mapargs('path,button,x,y,hold', ...)
+ args.button = args.button or 'LEFT'
+ local hold = args.hold or 1.0
+ wreq('mouseMove', args)
+ wreq('mouseDown', args)
+ Timer(hold, 'wait')
+ wreq('mouseUp', args)
+end
+
+-- pass a table as for UI.click()
+function UI.doubleclick(...)
+ local args = mapargs('path,button,x,y', ...)
+ args.button = args.button or 'LEFT'
+ wreq('mouseDown', args)
+ wreq('mouseUp', args)
+ wreq('mouseDown', args)
+ wreq('mouseUp', args)
+end
+
+-- UI.drag{path=, xoff=, yoff=}
+function UI.drag(...)
+ local args = mapargs('path,xoff,yoff', ...)
+ -- query the specified path
+ local rect = UI.viewinfo(args.path).rect
+ local centerx = math.floor(rect.left + (rect.right - rect.left)/2)
+ local centery = math.floor(rect.bottom + (rect.top - rect.bottom)/2)
+ wreq{op='mouseMove', path=args.path, x=centerx, y=centery}
+ wreq{op='mouseDown', path=args.path, button='LEFT'}
+ wreq{op='mouseMove', path=args.path, x=centerx + args.xoff, y=centery + args.yoff}
+ wreq{op='mouseUp', path=args.path, button='LEFT'}
+end
+
+-- ***************************************************************************
+-- keyboard actions
+-- ***************************************************************************
+-- pass a table:
+-- UI.keypress{
+-- [path=path] -- if omitted, default input field
+-- [, char='x'] -- requires one of char, keycode, keysym
+-- [, keycode=120]
+-- keysym per https://github.com/secondlife/viewer/blob/main/indra/llwindow/llkeyboard.cpp#L68-L124
+-- [, keysym='Enter']
+-- [, mask={'SHIFT', 'CTL', 'ALT', 'MAC_CONTROL'}] -- some subset of these
+-- }
+function UI.keypress(...)
+ local args = mapargs('path,char,keycode,keysym,mask', ...)
+ if args.char == '\n' then
+ args.char = nil
+ args.keysym = 'Enter'
+ end
+ return wreq('keyDown', args)
+end
+
+-- UI.type{text=, path=}
+function UI.type(...)
+ local args = mapargs('text,path', ...)
+ if #args.text > 0 then
+ -- The caller's path may be specified in a way that requires recursively
+ -- searching parts of the LLView tree. No point in doing that more than
+ -- once. Capture the actual path found by that first call and use that for
+ -- subsequent calls.
+ local path = UI.keypress{path=args.path, char=string.sub(args.text, 1, 1)}.path
+ for i = 2, #args.text do
+ UI.keypress{path=path, char=string.sub(args.text, i, i)}
+ end
+ end
+end
+
+-- ***************************************************************************
+-- Snapshot
+-- ***************************************************************************
+-- UI.snapshot{filename=filename -- extension may be specified: bmp, jpeg, png
+-- [, type='COLOR' | 'DEPTH']
+-- [, width=width][, height=height] -- uses current window size if not specified
+-- [, showui=true][, showhud=true]
+-- [, rebuild=false]}
+function UI.snapshot(...)
+ local args = mapargs('filename,width,height,showui,showhud,rebuild,type', ...)
+ args.op = 'saveSnapshot'
+ return leap.request('LLViewerWindow', args).result
+end
+
+-- ***************************************************************************
+-- Top menu
+-- ***************************************************************************
+
+function UI.getTopMenus()
+ return leap.request('UI', {op='getTopMenus'}).menus
+end
+
+function UI.addMenu(...)
+ local args = mapargs('name,label', ...)
+ args.op = 'addMenu'
+ return leap.request('UI', args)
+end
+
+function UI.setMenuVisible(name, visible)
+ return leap.request('UI', {op='setMenuVisible', name=name, visible=visible})
+end
+
+function UI.addMenuBranch(...)
+ local args = mapargs('name,label,parent_menu', ...)
+ args.op = 'addMenuBranch'
+ return leap.request('UI', args)
+end
+
+-- see UI.callables() for valid values of 'func'
+function UI.addMenuItem(...)
+ local args = mapargs('name,label,parent_menu,func,param,pos', ...)
+ args.op = 'addMenuItem'
+ return leap.request('UI', args)
+end
+
+function UI.addMenuSeparator(...)
+ local args = mapargs('parent_menu,pos', ...)
+ args.op = 'addMenuSeparator'
+ return leap.request('UI', args)
+end
+
+-- ***************************************************************************
+-- Toolbar buttons
+-- ***************************************************************************
+-- Clears all buttons off the toolbars
+function UI.clearAllToolbars()
+ leap.send('UI', {op='clearAllToolbars'})
+end
+
+function UI.defaultToolbars()
+ leap.send('UI', {op='defaultToolbars'})
+end
+
+-- UI.addToolbarBtn{btn_name=btn_name
+-- [, toolbar= bottom] -- left, right, bottom -- default is bottom
+-- [, rank=1]} -- position on the toolbar, starts at 0 (0 - first position, 1 - second position etc.)
+function UI.addToolbarBtn(...)
+ local args = mapargs('btn_name,toolbar,rank', ...)
+ args.op = 'addToolbarBtn'
+ return leap.request('UI', args)
+end
+
+-- Returns the rank(position) of the command in the original list
+function UI.removeToolbarBtn(btn_name)
+ return leap.request('UI', {op = 'removeToolbarBtn', btn_name=btn_name}).rank
+end
+
+function UI.getToolbarBtnNames()
+ return leap.request('UI', {op = 'getToolbarBtnNames'}).cmd_names
+end
+
+-- ***************************************************************************
+-- Floaters
+-- ***************************************************************************
+function UI.showFloater(floater_name)
+ leap.send("LLFloaterReg", {op = "showInstance", name = floater_name})
+end
+
+function UI.hideFloater(floater_name)
+ leap.send("LLFloaterReg", {op = "hideInstance", name = floater_name})
+end
+
+function UI.toggleFloater(...)
+ local args = mapargs('name,key', ...)
+ args.op = 'toggleInstance'
+ leap.send("LLFloaterReg", args)
+end
+
+function UI.isFloaterVisible(floater_name)
+ return leap.request("LLFloaterReg", {op = "instanceVisible", name = floater_name}).visible
+end
+
+function UI.closeAllFloaters()
+ return leap.send("UI", {op = "closeAllFloaters"})
+end
+
+function UI.getFloaterNames()
+ local key_length = leap.request("LLFloaterReg", {op = "getFloaterNames"}).floaters
+ local view = result_view(key_length)
+ return LL.setdtor('registered floater names', view, view.close)
+end
+
+return UI
diff --git a/indra/newview/scripts/lua/require/UI/Floater.lua b/indra/newview/scripts/lua/require/UI/Floater.lua
new file mode 100644
index 0000000000..d057a74386
--- /dev/null
+++ b/indra/newview/scripts/lua/require/UI/Floater.lua
@@ -0,0 +1,146 @@
+-- Floater base class
+
+local leap = require 'leap'
+local fiber = require 'fiber'
+local util = require 'util'
+
+-- list of all the events that a LLLuaFloater might send
+local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events
+local event_set = {}
+for _, event in pairs(event_list) do
+ event_set[event] = true
+end
+
+local function _event(event_name)
+ if not event_set[event_name] then
+ error("Incorrect event name: " .. event_name, 3)
+ end
+ return event_name
+end
+
+-- ---------------------------------------------------------------------------
+local Floater = {}
+
+-- Pass:
+-- relative file path to floater's XUI definition file
+-- optional: sign up for additional events for defined control
+-- {<control_name>={action1, action2, ...}}
+function Floater:new(path, extra)
+ local obj = setmetatable({}, self)
+ self.__index = self
+
+ local path_parts = string.split(path, '/')
+ obj.name = 'Floater ' .. path_parts[#path_parts]
+
+ obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)}
+ if extra then
+ -- validate each of the actions for each specified control
+ for control, actions in pairs(extra) do
+ for _, action in pairs(actions) do
+ _event(action)
+ end
+ end
+ obj._command.extra_events = extra
+ end
+
+ return obj
+end
+
+util.classctor(Floater)
+
+function Floater:show()
+ -- leap.eventstream() returns the first response, and launches a
+ -- background fiber to call the passed callback with all subsequent
+ -- responses.
+ local event = leap.eventstream(
+ 'LLFloaterReg',
+ self._command,
+ -- handleEvents() returns false when done.
+ -- eventstream() expects a true return when done.
+ function(event) return not self:handleEvents(event) end)
+ self._pump = event.command_name
+ -- we might need the returned reqid to cancel the eventstream() fiber
+ self.reqid = event.reqid
+
+ -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if
+ -- subclass has a post_build() method. Honor the convention that if
+ -- handleEvents() returns false, we're done.
+ if not self:handleEvents(event) then
+ return
+ end
+end
+
+function Floater:post(action)
+ leap.send(self._pump, action)
+end
+
+function Floater:request(action)
+ return leap.request(self._pump, action)
+end
+
+-- local inspect = require 'inspect'
+
+function Floater:handleEvents(event_data)
+ local event = event_data.event
+ if event_set[event] == nil then
+ LL.print_warning(string.format('%s received unknown event %q', self.name, event))
+ end
+
+ -- Before checking for a general (e.g.) commit() method, first look for
+ -- commit_ctrl_name(): in other words, concatenate the event name with the
+ -- ctrl_name, with an underscore between. If there exists such a specific
+ -- method, call that.
+ local handler, ret
+ if event_data.ctrl_name then
+ local specific = event .. '_' .. event_data.ctrl_name
+ handler = self[specific]
+ if handler then
+ ret = handler(self, event_data)
+ -- Avoid 'return ret or true' because we explicitly want to allow
+ -- the handler to return false.
+ if ret ~= nil then
+ return ret
+ else
+ return true
+ end
+ end
+ end
+
+ -- No specific "event_on_ctrl()" method found; try just "event()"
+ handler = self[event]
+ if handler then
+ ret = handler(self, event_data)
+ if ret ~= nil then
+ return ret
+ end
+-- else
+-- print(string.format('%s ignoring event %s', self.name, inspect(event_data)))
+ end
+
+ -- We check for event() method before recognizing floater_close in case
+ -- the consumer needs to react specially to closing the floater. Now that
+ -- we've checked, recognize it ourselves. Returning false terminates the
+ -- anonymous fiber function launched by leap.eventstream().
+ if event == _event('floater_close') then
+ LL.print_warning(self.name .. ' closed')
+ return false
+ end
+ return true
+end
+
+-- onCtrl() permits a different dispatch style in which the general event()
+-- method explicitly calls (e.g.)
+-- self:onCtrl(event_data, {
+-- ctrl_name=function()
+-- self:post(...)
+-- end,
+-- ...
+-- })
+function Floater:onCtrl(event_data, ctrl_map)
+ local handler = ctrl_map[event_data.ctrl_name]
+ if handler then
+ handler()
+ end
+end
+
+return Floater
diff --git a/indra/newview/scripts/lua/require/UI/popup.lua b/indra/newview/scripts/lua/require/UI/popup.lua
new file mode 100644
index 0000000000..8ccf3b87f3
--- /dev/null
+++ b/indra/newview/scripts/lua/require/UI/popup.lua
@@ -0,0 +1,82 @@
+local leap = require 'leap'
+local mapargs = require 'mapargs'
+local util = require 'util'
+
+-- notification is any name defined in notifications.xml as
+-- <notification name=>
+-- vars is a table providing values for [VAR] substitution keys in the
+-- notification body
+-- payload prepopulates the response table
+-- wait=false means fire and forget, returning nil
+-- wait=true waits for user response:
+-- * If the viewer returns a table containing exactly one key=true pair,
+-- popup() returns just that key. If the key is a string containing an
+-- underscore, e.g. 'OK_okcancelbuttons', it's truncated at the first
+-- underscore, e.g. 'OK'.
+-- * Otherwise the viewer's response is returned unchanged. To suppress the
+-- above transformations, pass a non-empty payload table; this will cause
+-- the viewer to return a table with at least two keys.
+local popup = util.setmetamethods{
+ -- this gets called when a consumer calls popup(notification, vars, payload)
+ __call = function(self, ...)
+ local args = mapargs('notification,vars,payload,wait', ...)
+ -- we use convenience argument names different from 'LLNotifications'
+ -- listener
+ newargs = {op='requestAdd',
+ name=args.notification,
+ substitutions=args.vars,
+ payload=args.payload}
+ -- Specifically test (wait == false), NOT (not wait), because we treat
+ -- nil (omitted, default true) differently than false (explicitly
+ -- DON'T wait).
+ if args.wait == false then
+ leap.send('LLNotifications', newargs)
+ else
+ local response = leap.request('LLNotifications', newargs).response
+ -- response is typically a table. It might have multiple keys,
+ -- e.g. if caller passed non-empty payload. In that case, just
+ -- return the whole thing.
+ if type(response) ~= 'table' then
+ return response
+ end
+ -- get first key=value pair, if any
+ local key, value = next(response)
+ if (not key) or next(response, key) then
+ -- key == nil means response is empty
+ -- next(response, non-nil first key) ~= nil means at least two keys
+ return response
+ end
+ -- Here response is a table containing exactly one key. The
+ -- notifications system typically returns a table of the form
+ -- {OK_okcancelbuttons=true}, which is tricky to test for because it
+ -- varies with each set of buttons.
+ if value == true then
+ -- change {key=true} to plain key
+ response = key
+ if type(response) == 'string' then
+ -- change 'OK_okcancelbuttons' to plain 'OK'
+ response = string.split(response, '_')[1]
+ end
+ end
+ return response
+ end
+ end
+}
+
+function popup:alert(message, payload)
+ return self('GenericAlert', {MESSAGE=message, payload=payload})
+end
+
+function popup:alertOK(message, payload)
+ return self('GenericAlertOK', {MESSAGE=message, payload=payload})
+end
+
+function popup:alertYesCancel(message, payload)
+ return self('GenericAlertYesCancel', {MESSAGE=message, payload=payload})
+end
+
+function popup:tip(message, payload)
+ self{'SystemMessageTip', {MESSAGE=message, payload=payload}, wait=false}
+end
+
+return popup
diff --git a/indra/newview/scripts/lua/require/WaitQueue.lua b/indra/newview/scripts/lua/require/WaitQueue.lua
new file mode 100644
index 0000000000..7e10d03295
--- /dev/null
+++ b/indra/newview/scripts/lua/require/WaitQueue.lua
@@ -0,0 +1,88 @@
+-- WaitQueue isa Queue with the added feature that when the queue is empty,
+-- the Dequeue() operation blocks the calling coroutine until some other
+-- coroutine Enqueue()s a new value.
+
+local fiber = require('fiber')
+local Queue = require('Queue')
+local util = require('util')
+
+local function dbg(...) end
+-- local dbg = require('printf')
+
+local WaitQueue = Queue()
+
+function WaitQueue:new()
+ local obj = Queue()
+ setmetatable(obj, self)
+ self.__index = self
+
+ obj._waiters = {}
+ obj._closed = false
+ return obj
+end
+
+util.classctor(WaitQueue)
+
+function WaitQueue:Enqueue(value)
+ if self._closed then
+ error("can't Enqueue() on closed Queue")
+ end
+ -- can't simply call Queue:Enqueue(value)! That calls the method on the
+ -- Queue class definition, instead of calling Queue:Enqueue() on self.
+ -- Hand-expand the Queue:Enqueue() syntactic sugar.
+ Queue.Enqueue(self, value)
+ self:_wake_waiters()
+end
+
+function WaitQueue:_wake_waiters()
+ -- WaitQueue is designed to support multi-producer, multi-consumer use
+ -- cases. With multiple consumers, if more than one is trying to
+ -- Dequeue() from an empty WaitQueue, we'll have multiple waiters.
+ -- Unlike OS threads, with cooperative concurrency it doesn't make sense
+ -- to "notify all": we need wake only one of the waiting Dequeue()
+ -- callers.
+ if ((not self:IsEmpty()) or self._closed) and next(self._waiters) then
+ -- Pop the oldest waiting coroutine instead of the most recent, for
+ -- more-or-less round robin fairness. But skip any coroutines that
+ -- have gone dead in the meantime.
+ local waiter = table.remove(self._waiters, 1)
+ while waiter and fiber.status(waiter) == "dead" do
+ waiter = table.remove(self._waiters, 1)
+ end
+ -- do we still have at least one waiting coroutine?
+ if waiter then
+ -- don't pass the head item: let the resumed coroutine retrieve it
+ fiber.wake(waiter)
+ end
+ end
+end
+
+function WaitQueue:Dequeue()
+ while self:IsEmpty() do
+ -- Don't check for closed until the queue is empty: producer can close
+ -- the queue while there are still items left, and we want the
+ -- consumer(s) to retrieve those last few items.
+ if self._closed then
+ dbg('WaitQueue:Dequeue(): closed')
+ return nil
+ end
+ dbg('WaitQueue:Dequeue(): waiting')
+ -- add the running coroutine to the list of waiters
+ dbg('WaitQueue:Dequeue() running %s', tostring(coroutine.running() or 'main'))
+ table.insert(self._waiters, fiber.running())
+ -- then let somebody else run
+ fiber.wait()
+ end
+ -- here we're sure this queue isn't empty
+ dbg('WaitQueue:Dequeue() calling Queue.Dequeue()')
+ return Queue.Dequeue(self)
+end
+
+function WaitQueue:close()
+ self._closed = true
+ -- close() is like Enqueueing an end marker. If there are waiting
+ -- consumers, give them a chance to see we're closed.
+ self:_wake_waiters()
+end
+
+return WaitQueue
diff --git a/indra/newview/scripts/lua/require/coro.lua b/indra/newview/scripts/lua/require/coro.lua
new file mode 100644
index 0000000000..616a797e95
--- /dev/null
+++ b/indra/newview/scripts/lua/require/coro.lua
@@ -0,0 +1,67 @@
+-- Manage Lua coroutines
+
+local coro = {}
+
+coro._coros = {}
+
+-- Launch a Lua coroutine: create and resume.
+-- Returns: new coroutine, values yielded or returned from initial resume()
+-- If initial resume() encountered an error, propagates the error.
+function coro.launch(func, ...)
+ local co = coroutine.create(func)
+ table.insert(coro._coros, co)
+ return co, coro.resume(co, ...)
+end
+
+-- resume() wrapper to propagate errors
+function coro.resume(co, ...)
+ -- if there's an idiom other than table.pack() to assign an arbitrary
+ -- number of return values, I don't yet know it
+ local ok_result = table.pack(coroutine.resume(co, ...))
+ if not ok_result[1] then
+ -- if [1] is false, then [2] is the error message
+ error(ok_result[2])
+ end
+ -- ok is true, whew, just return the rest of the values
+ return table.unpack(ok_result, 2)
+end
+
+-- yield to other coroutines even if you don't know whether you're in a
+-- created coroutine or the main coroutine
+function coro.yield(...)
+ if coroutine.running() then
+ -- this is a real coroutine, yield normally
+ return coroutine.yield(...)
+ else
+ -- This is the main coroutine: coroutine.yield() doesn't work.
+ -- But we can take a spin through previously-launched coroutines.
+ -- Walk a copy of coro._coros in case any of these coroutines launches
+ -- another: next() forbids creating new entries during traversal.
+ for co in coro._live_coros_iter, table.clone(coro._coros) do
+ coro.resume(co)
+ end
+ end
+end
+
+-- Walk coro._coros table, returning running or suspended coroutines.
+-- Once a coroutine becomes dead, remove it from _coros and don't return it.
+function coro._live_coros()
+ return coro._live_coros_iter, coro._coros
+end
+
+-- iterator function for _live_coros()
+function coro._live_coros_iter(t, idx)
+ local k, co = next(t, idx)
+ while k and coroutine.status(co) == 'dead' do
+-- t[k] = nil
+ -- See coro.yield(): sometimes we traverse a copy of _coros, but if we
+ -- discover a dead coroutine in that copy, delete it from _coros
+ -- anyway. Deleting it from a temporary copy does nothing.
+ coro._coros[k] = nil
+ coroutine.close(co)
+ k, co = next(t, k)
+ end
+ return co
+end
+
+return coro
diff --git a/indra/newview/scripts/lua/require/fiber.lua b/indra/newview/scripts/lua/require/fiber.lua
new file mode 100644
index 0000000000..b3c684dd67
--- /dev/null
+++ b/indra/newview/scripts/lua/require/fiber.lua
@@ -0,0 +1,346 @@
+-- Organize Lua coroutines into fibers.
+
+-- In this usage, the difference between coroutines and fibers is that fibers
+-- have a scheduler. Yielding a fiber means allowing other fibers, plural, to
+-- run: it's more than just returning control to the specific Lua thread that
+-- resumed the running coroutine.
+
+-- fiber.launch() creates a new fiber ready to run.
+-- fiber.status() reports (augmented) status of the passed fiber: instead of
+-- 'suspended', it returns either 'ready' or 'waiting'
+-- fiber.yield() allows other fibers to run, but leaves the calling fiber
+-- ready to run.
+-- fiber.wait() marks the running fiber not ready, and resumes other fibers.
+-- fiber.wake() marks the designated suspended fiber ready to run, but does
+-- not yet resume it.
+-- fiber.run() runs all current fibers until all have terminated (successfully
+-- or with an error).
+
+local printf = require 'printf'
+local function dbg(...) end
+-- local dbg = printf
+local coro = require 'coro'
+
+local fiber = {}
+
+-- The tables in which we track fibers must have weak keys so dead fibers
+-- can be garbage-collected.
+local weak_values = {__mode='v'}
+local weak_keys = {__mode='k'}
+
+-- Track each current fiber as being either ready to run or not ready
+-- (waiting). wait() moves the running fiber from ready to waiting; wake()
+-- moves the designated fiber from waiting back to ready.
+-- The ready table is used as a list so yield() can go round robin.
+local ready = setmetatable({'main'}, weak_keys)
+-- The waiting table is used as a set because order doesn't matter.
+local waiting = setmetatable({}, weak_keys)
+
+-- Every fiber has a name, for diagnostic purposes. Names must be unique.
+-- A colliding name will be suffixed with an integer.
+-- Predefine 'main' with our marker so nobody else claims that name.
+local names = setmetatable({main='main'}, weak_keys)
+local byname = setmetatable({main='main'}, weak_values)
+-- each colliding name has its own distinct suffix counter
+local suffix = {}
+
+-- Specify a nullary idle() callback to be called whenever there are no ready
+-- fibers but there are waiting fibers. The idle() callback is responsible for
+-- changing zero or more waiting fibers to ready fibers by calling
+-- fiber.wake(), although a given call may leave them all still waiting.
+-- When there are no ready fibers, it's a good idea for the idle() function to
+-- return control to a higher-level execution agent. Simply returning without
+-- changing any fiber's status will spin the CPU.
+-- The idle() callback can return non-nil to exit fiber.run() with that value.
+function fiber._idle()
+ error('fiber.yield(): you must first call set_idle(nullary idle() function)')
+end
+
+function fiber.set_idle(func)
+ fiber._idle = func
+end
+
+-- Launch a new Lua fiber, ready to run.
+function fiber.launch(name, func, ...)
+ local args = table.pack(...)
+ local co = coroutine.create(function() func(table.unpack(args)) end)
+ -- a new fiber is ready to run
+ table.insert(ready, co)
+ local namekey = name
+ while byname[namekey] do
+ if not suffix[name] then
+ suffix[name] = 1
+ end
+ suffix[name] += 1
+ namekey = name .. tostring(suffix[name])
+ end
+ -- found a namekey not yet in byname: set it
+ byname[namekey] = co
+ -- and remember it as this fiber's name
+ names[co] = namekey
+-- dbg('launch(%s)', namekey)
+-- dbg('byname[%s] = %s', namekey, tostring(byname[namekey]))
+-- dbg('names[%s] = %s', tostring(co), names[co])
+-- dbg('ready[-1] = %s', tostring(ready[#ready]))
+end
+
+-- for debugging
+function format_all()
+ output = {}
+ table.insert(output, 'Ready fibers:' .. if next(ready) then '' else ' none')
+ for _, co in pairs(ready) do
+ table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co)))
+ end
+ table.insert(output, 'Waiting fibers:' .. if next(waiting) then '' else ' none')
+ for co in pairs(waiting) do
+ table.insert(output, string.format(' %s: %s', fiber.get_name(co), fiber.status(co)))
+ end
+ return table.concat(output, '\n')
+end
+
+function fiber.print_all()
+ print(format_all())
+end
+
+-- return either the running coroutine or, if called from the main thread,
+-- 'main'
+function fiber.running()
+ return coroutine.running() or 'main'
+end
+
+-- Query a fiber's name (nil for the running fiber)
+function fiber.get_name(co)
+ return names[co or fiber.running()] or 'unknown'
+end
+
+-- Query status of the passed fiber
+function fiber.status(co)
+ local running = coroutine.running()
+ if (not co) or co == running then
+ -- silly to ask the status of the running fiber: it's 'running'
+ return 'running'
+ end
+ if co ~= 'main' then
+ -- for any coroutine but main, consult coroutine.status()
+ local status = coroutine.status(co)
+ if status ~= 'suspended' then
+ return status
+ end
+ -- here co is suspended, answer needs further refinement
+ else
+ -- co == 'main'
+ if not running then
+ -- asking about 'main' from the main fiber
+ return 'running'
+ end
+ -- asking about 'main' from some other fiber, so presumably main is suspended
+ end
+ -- here we know co is suspended -- but is it ready to run?
+ if waiting[co] then
+ return 'waiting'
+ end
+ -- not waiting should imply ready: sanity check
+ if table.find(ready, co) then
+ return 'ready'
+ end
+ -- Calls within yield() between popping the next ready fiber and
+ -- re-appending it to the list are in this state. Once we're done
+ -- debugging yield(), we could reinstate either of the below.
+-- error(string.format('fiber.status(%s) is stumped', fiber.get_name(co)))
+-- print(string.format('*** fiber.status(%s) is stumped', fiber.get_name(co)))
+ return '(unknown)'
+end
+
+-- change the running fiber's status to waiting
+local function set_waiting()
+ -- if called from the main fiber, inject a 'main' marker into the list
+ co = fiber.running()
+ -- delete from ready list
+ local i = table.find(ready, co)
+ if i then
+ table.remove(ready, i)
+ end
+ -- add to waiting list
+ waiting[co] = true
+end
+
+-- Suspend the current fiber until some other fiber calls fiber.wake() on it
+function fiber.wait()
+ dbg('Fiber %q waiting', fiber.get_name())
+ set_waiting()
+ -- now yield to other fibers
+ fiber.yield()
+end
+
+-- Mark a suspended fiber as being ready to run
+function fiber.wake(co)
+ if not waiting[co] then
+ error(string.format('fiber.wake(%s) but status=%s, ready=%s, waiting=%s',
+ names[co], fiber.status(co), ready[co], waiting[co]))
+ end
+ -- delete from waiting list
+ waiting[co] = nil
+ -- add to end of ready list
+ table.insert(ready, co)
+ dbg('Fiber %q ready', fiber.get_name(co))
+ -- but don't yet resume it: that happens next time we reach yield()
+end
+
+-- pop and return the next not-dead fiber in the ready list, or nil if none remain
+local function live_ready_iter()
+ -- don't write:
+ -- for co in table.remove, ready, 1
+ -- because it would keep passing a new second parameter!
+ for co in function() return table.remove(ready, 1) end do
+ dbg('%s live_ready_iter() sees %s, status %s',
+ fiber.get_name(), fiber.get_name(co), fiber.status(co))
+ -- keep removing the head entry until we find one that's not dead,
+ -- discarding any dead coroutines along the way
+ if co == 'main' or coroutine.status(co) ~= 'dead' then
+ dbg('%s live_ready_iter() returning %s',
+ fiber.get_name(), fiber.get_name(co))
+ return co
+ end
+ end
+ dbg('%s live_ready_iter() returning nil', fiber.get_name())
+ return nil
+end
+
+-- prune the set of waiting fibers
+local function prune_waiting()
+ for waiter in pairs(waiting) do
+ if waiter ~= 'main' and coroutine.status(waiter) == 'dead' then
+ waiting[waiter] = nil
+ end
+ end
+end
+
+-- Run other ready fibers, leaving this one ready, returning after a cycle.
+-- Returns:
+-- * true, nil if there remain other live fibers, whether ready or waiting,
+-- but it's our turn to run
+-- * false, nil if this is the only remaining fiber
+-- * nil, x if configured idle() callback returns non-nil x
+local function scheduler()
+ dbg('scheduler():\n%s', format_all())
+ -- scheduler() is asymmetric because Lua distinguishes the main thread
+ -- from other coroutines. The main thread can't yield; it can only resume
+ -- other coroutines. So although an arbitrary coroutine could resume still
+ -- other arbitrary coroutines, it could NOT resume the main thread because
+ -- the main thread can't yield. Therefore, scheduler() delegates its real
+ -- processing to the main thread. If called from a coroutine, pass control
+ -- back to the main thread.
+ if coroutine.running() then
+ -- this is a real coroutine, yield normally to main thread
+ coroutine.yield()
+ -- main certainly still exists
+ return true
+ end
+
+ -- This is the main fiber: coroutine.yield() doesn't work.
+ -- Instead, resume each of the ready fibers.
+ -- Prune the set of waiting fibers after every time fiber business logic
+ -- runs (i.e. other fibers might have terminated or hit error), such as
+ -- here on entry.
+ prune_waiting()
+ local others, idle_stop
+ repeat
+ for co in live_ready_iter do
+ -- seize the opportunity to make sure the viewer isn't shutting down
+ LL.check_stop()
+ -- before we re-append co, is it the only remaining entry?
+ others = next(ready)
+ -- co is live, re-append it to the ready list
+ table.insert(ready, co)
+ if co == 'main' then
+ -- Since we know the caller is the main fiber, it's our turn.
+ -- Tell caller if there are other ready or waiting fibers.
+ return others or next(waiting)
+ end
+ -- not main, but some other ready coroutine:
+ -- use coro.resume() so we'll propagate any error encountered
+ coro.resume(co)
+ prune_waiting()
+ end
+ -- Here there are no ready fibers. Are there any waiting fibers?
+ if not next(waiting) then
+ return false
+ end
+ -- there are waiting fibers: call consumer's configured idle() function
+ idle_stop = fiber._idle()
+ if idle_stop ~= nil then
+ return nil, idle_stop
+ end
+ prune_waiting()
+ -- loop "forever", that is, until:
+ -- * main is ready, or
+ -- * there are neither ready fibers nor waiting fibers, or
+ -- * fiber._idle() returned non-nil
+ until false
+end
+
+-- Let other fibers run. This is useful in either of two cases:
+-- * fiber.wait() calls this to run other fibers while this one is waiting.
+-- fiber.yield() (and therefore fiber.wait()) works from the main thread as
+-- well as from explicitly-launched fibers, without the caller having to
+-- care.
+-- * A long-running fiber that doesn't often call fiber.wait() should sprinkle
+-- in fiber.yield() calls to interleave processing on other fibers.
+function fiber.yield()
+ -- The difference between this and fiber.run() is that fiber.yield()
+ -- assumes its caller has work to do. yield() returns to its caller as
+ -- soon as scheduler() pops this fiber from the ready list. fiber.run()
+ -- continues looping until all other fibers have terminated, or the
+ -- set_idle() callback tells it to stop.
+ local others, idle_done = scheduler()
+ -- scheduler() returns either if we're ready, or if idle_done ~= nil.
+ if idle_done ~= nil then
+ -- Returning normally from yield() means the caller can carry on with
+ -- its pending work. But in this case scheduler() returned because the
+ -- configured set_idle() function interrupted it -- not because we're
+ -- actually ready. Don't return normally.
+ error('fiber.set_idle() interrupted yield() with: ' .. tostring(idle_done))
+ end
+ -- We're ready! Just return to caller. In this situation we don't care
+ -- whether there are other ready fibers.
+ dbg('fiber.yield() returning to %s (%sothers are ready)',
+ fiber.get_name(), ((not others) and "no " or ""))
+end
+
+-- Run fibers until all but main have terminated: return nil.
+-- Or until configured idle() callback returns x ~= nil: return x.
+function fiber.run()
+ -- A fiber calling run() is not also doing other useful work. Remove the
+ -- calling fiber from the ready list. Otherwise yield() would keep seeing
+ -- that our caller is ready and return to us, instead of realizing that
+ -- all coroutines are waiting and call idle(). But don't say we're
+ -- waiting, either, because then when all other fibers have terminated
+ -- we'd call idle() forever waiting for something to make us ready again.
+ local i = table.find(ready, fiber.running())
+ if i then
+ table.remove(ready, i)
+ end
+ local others, idle_done
+ repeat
+ dbg('%s calling fiber.run() calling scheduler()', fiber.get_name())
+ others, idle_done = scheduler()
+ dbg("%s fiber.run()'s scheduler() returned %s, %s", fiber.get_name(),
+ tostring(others), tostring(idle_done))
+ until (not others)
+ dbg('%s fiber.run() done', fiber.get_name())
+ -- For whatever it's worth, put our own fiber back in the ready list.
+ table.insert(ready, fiber.running())
+ -- Once there are no more waiting fibers, and the only ready fiber is
+ -- us, return to caller. All previously-launched fibers are done. Possibly
+ -- the chunk is done, or the chunk may decide to launch a new batch of
+ -- fibers.
+ return idle_done
+end
+
+-- Make sure we finish up with a call to run(). That allows a consuming script
+-- to kick off some number of fibers, do some work on the main thread and then
+-- fall off the end of the script without explicitly calling fiber.run().
+-- run() ensures the rest of the fibers run to completion (or error).
+LL.atexit(fiber.run)
+
+return fiber
diff --git a/indra/newview/scripts/lua/require/inspect.lua b/indra/newview/scripts/lua/require/inspect.lua
new file mode 100644
index 0000000000..9900a0b81b
--- /dev/null
+++ b/indra/newview/scripts/lua/require/inspect.lua
@@ -0,0 +1,371 @@
+local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local math = _tl_compat and _tl_compat.math or math; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table
+local inspect = {Options = {}, }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+inspect._VERSION = 'inspect.lua 3.1.0'
+inspect._URL = 'http://github.com/kikito/inspect.lua'
+inspect._DESCRIPTION = 'human-readable representations of tables'
+inspect._LICENSE = [[
+ MIT LICENSE
+
+ Copyright (c) 2022 Enrique García Cota
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+]]
+inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end })
+inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end })
+
+local tostring = tostring
+local rep = string.rep
+local match = string.match
+local char = string.char
+local gsub = string.gsub
+local fmt = string.format
+
+local _rawget
+if rawget then
+ _rawget = rawget
+else
+ _rawget = function(t, k) return t[k] end
+end
+
+local function rawpairs(t)
+ return next, t, nil
+end
+
+
+
+local function smartQuote(str)
+ if match(str, '"') and not match(str, "'") then
+ return "'" .. str .. "'"
+ end
+ return '"' .. gsub(str, '"', '\\"') .. '"'
+end
+
+
+local shortControlCharEscapes = {
+ ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
+ ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\127"] = "\\127",
+}
+local longControlCharEscapes = { ["\127"] = "\127" }
+for i = 0, 31 do
+ local ch = char(i)
+ if not shortControlCharEscapes[ch] then
+ shortControlCharEscapes[ch] = "\\" .. i
+ longControlCharEscapes[ch] = fmt("\\%03d", i)
+ end
+end
+
+local function escape(str)
+ return (gsub(gsub(gsub(str, "\\", "\\\\"),
+ "(%c)%f[0-9]", longControlCharEscapes),
+ "%c", shortControlCharEscapes))
+end
+
+local luaKeywords = {
+ ['and'] = true,
+ ['break'] = true,
+ ['do'] = true,
+ ['else'] = true,
+ ['elseif'] = true,
+ ['end'] = true,
+ ['false'] = true,
+ ['for'] = true,
+ ['function'] = true,
+ ['goto'] = true,
+ ['if'] = true,
+ ['in'] = true,
+ ['local'] = true,
+ ['nil'] = true,
+ ['not'] = true,
+ ['or'] = true,
+ ['repeat'] = true,
+ ['return'] = true,
+ ['then'] = true,
+ ['true'] = true,
+ ['until'] = true,
+ ['while'] = true,
+}
+
+local function isIdentifier(str)
+ return type(str) == "string" and
+ not not str:match("^[_%a][_%a%d]*$") and
+ not luaKeywords[str]
+end
+
+local flr = math.floor
+local function isSequenceKey(k, sequenceLength)
+ return type(k) == "number" and
+ flr(k) == k and
+ 1 <= (k) and
+ k <= sequenceLength
+end
+
+local defaultTypeOrders = {
+ ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
+ ['function'] = 5, ['userdata'] = 6, ['thread'] = 7,
+}
+
+local function sortKeys(a, b)
+ local ta, tb = type(a), type(b)
+
+
+ if ta == tb and (ta == 'string' or ta == 'number') then
+ return (a) < (b)
+ end
+
+ local dta = defaultTypeOrders[ta] or 100
+ local dtb = defaultTypeOrders[tb] or 100
+
+
+ return dta == dtb and ta < tb or dta < dtb
+end
+
+local function getKeys(t)
+
+ local seqLen = 1
+ while _rawget(t, seqLen) ~= nil do
+ seqLen = seqLen + 1
+ end
+ seqLen = seqLen - 1
+
+ local keys, keysLen = {}, 0
+ for k in rawpairs(t) do
+ if not isSequenceKey(k, seqLen) then
+ keysLen = keysLen + 1
+ keys[keysLen] = k
+ end
+ end
+ table.sort(keys, sortKeys)
+ return keys, keysLen, seqLen
+end
+
+local function countCycles(x, cycles)
+ if type(x) == "table" then
+ if cycles[x] then
+ cycles[x] = cycles[x] + 1
+ else
+ cycles[x] = 1
+ for k, v in rawpairs(x) do
+ countCycles(k, cycles)
+ countCycles(v, cycles)
+ end
+ countCycles(getmetatable(x), cycles)
+ end
+ end
+end
+
+local function makePath(path, a, b)
+ local newPath = {}
+ local len = #path
+ for i = 1, len do newPath[i] = path[i] end
+
+ newPath[len + 1] = a
+ newPath[len + 2] = b
+
+ return newPath
+end
+
+
+local function processRecursive(process,
+ item,
+ path,
+ visited)
+ if item == nil then return nil end
+ if visited[item] then return visited[item] end
+
+ local processed = process(item, path)
+ if type(processed) == "table" then
+ local processedCopy = {}
+ visited[item] = processedCopy
+ local processedKey
+
+ for k, v in rawpairs(processed) do
+ processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
+ if processedKey ~= nil then
+ processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
+ end
+ end
+
+ local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
+ if type(mt) ~= 'table' then mt = nil end
+ setmetatable(processedCopy, mt)
+ processed = processedCopy
+ end
+ return processed
+end
+
+local function puts(buf, str)
+ buf.n = buf.n + 1
+ buf[buf.n] = str
+end
+
+
+
+local Inspector = {}
+
+
+
+
+
+
+
+
+
+
+local Inspector_mt = { __index = Inspector }
+
+local function tabify(inspector)
+ puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level))
+end
+
+function Inspector:getId(v)
+ local id = self.ids[v]
+ local ids = self.ids
+ if not id then
+ local tv = type(v)
+ id = (ids[tv] or 0) + 1
+ ids[v], ids[tv] = id, id
+ end
+ return tostring(id)
+end
+
+function Inspector:putValue(v)
+ local buf = self.buf
+ local tv = type(v)
+ if tv == 'string' then
+ puts(buf, smartQuote(escape(v)))
+ elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
+ tv == 'cdata' or tv == 'ctype' then
+ puts(buf, tostring(v))
+ elseif tv == 'table' and not self.ids[v] then
+ local t = v
+
+ if t == inspect.KEY or t == inspect.METATABLE then
+ puts(buf, tostring(t))
+ elseif self.level >= self.depth then
+ puts(buf, '{...}')
+ else
+ if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end
+
+ local keys, keysLen, seqLen = getKeys(t)
+
+ puts(buf, '{')
+ self.level = self.level + 1
+
+ for i = 1, seqLen + keysLen do
+ if i > 1 then puts(buf, ',') end
+ if i <= seqLen then
+ puts(buf, ' ')
+ self:putValue(t[i])
+ else
+ local k = keys[i - seqLen]
+ tabify(self)
+ if isIdentifier(k) then
+ puts(buf, k)
+ else
+ puts(buf, "[")
+ self:putValue(k)
+ puts(buf, "]")
+ end
+ puts(buf, ' = ')
+ self:putValue(t[k])
+ end
+ end
+
+ local mt = getmetatable(t)
+ if type(mt) == 'table' then
+ if seqLen + keysLen > 0 then puts(buf, ',') end
+ tabify(self)
+ puts(buf, '<metatable> = ')
+ self:putValue(mt)
+ end
+
+ self.level = self.level - 1
+
+ if keysLen > 0 or type(mt) == 'table' then
+ tabify(self)
+ elseif seqLen > 0 then
+ puts(buf, ' ')
+ end
+
+ puts(buf, '}')
+ end
+
+ else
+ puts(buf, fmt('<%s %d>', tv, self:getId(v)))
+ end
+end
+
+
+
+
+function inspect.inspect(root, options)
+ options = options or {}
+
+ local depth = options.depth or (math.huge)
+ local newline = options.newline or '\n'
+ local indent = options.indent or ' '
+ local process = options.process
+
+ if process then
+ root = processRecursive(process, root, {}, {})
+ end
+
+ local cycles = {}
+ countCycles(root, cycles)
+
+ local inspector = setmetatable({
+ buf = { n = 0 },
+ ids = {},
+ cycles = cycles,
+ depth = depth,
+ level = 0,
+ newline = newline,
+ indent = indent,
+ }, Inspector_mt)
+
+ inspector:putValue(root)
+
+ return table.concat(inspector.buf)
+end
+
+setmetatable(inspect, {
+ __call = function(_, root, options)
+ return inspect.inspect(root, options)
+ end,
+})
+
+return inspect
diff --git a/indra/newview/scripts/lua/require/leap.lua b/indra/newview/scripts/lua/require/leap.lua
new file mode 100644
index 0000000000..82f91ce9e9
--- /dev/null
+++ b/indra/newview/scripts/lua/require/leap.lua
@@ -0,0 +1,550 @@
+-- Lua implementation of LEAP (LLSD Event API Plugin) protocol
+--
+-- This module supports Lua scripts run by the Second Life viewer.
+--
+-- LEAP protocol passes LLSD objects, converted to/from Lua tables, in both
+-- directions. A typical LLSD object is a map containing keys 'pump' and
+-- 'data'.
+--
+-- The viewer's Lua post_to(pump, data) function posts 'data' to the
+-- LLEventPump 'pump'. This is typically used to engage an LLEventAPI method.
+--
+-- Similarly, the viewer gives each Lua script its own LLEventPump with a
+-- unique name. That name is returned by get_event_pumps(). Every event
+-- received on that LLEventPump is queued for retrieval by get_event_next(),
+-- which returns (pump, data): the name of the LLEventPump on which the event
+-- was received and the received event data. When the queue is empty,
+-- get_event_next() blocks the calling Lua script until the next event is
+-- received.
+--
+-- Usage:
+-- 1. Launch some number of Lua coroutines. The code in each coroutine may
+-- call leap.send(), leap.request() or leap.generate(). leap.send() returns
+-- immediately ("fire and forget"). leap.request() blocks the calling
+-- coroutine until it receives and returns the viewer's response to its
+-- request. leap.generate() expects an arbitrary number of responses to the
+-- original request.
+-- 2. To handle events from the viewer other than direct responses to
+-- requests, instantiate a leap.WaitFor object with a filter(pump, data)
+-- override method that returns non-nil for desired events. A coroutine may
+-- call wait() on any such WaitFor.
+-- 3. Once the coroutines have been launched, call leap.process() on the main
+-- coroutine. process() retrieves incoming events from the viewer and
+-- dispatches them to waiting request() or generate() calls, or to
+-- appropriate WaitFor instances. process() returns when either
+-- get_event_next() raises an error or the viewer posts nil to the script's
+-- reply pump to indicate it's done.
+-- 4. Alternatively, a running coroutine may call leap.done() to break out of
+-- leap.process(). process() won't notice until the next event from the
+-- viewer, though.
+
+local fiber = require('fiber')
+local ErrorQueue = require('ErrorQueue')
+local inspect = require('inspect')
+local function dbg(...) end
+-- local dbg = require('printf')
+local util = require('util')
+
+local leap = {}
+
+-- reply: string name of reply LLEventPump. Any events the viewer posts to
+-- this pump will be queued for get_event_next(). We usually specify it as the
+-- reply pump for requests to internal viewer services.
+-- command: string name of command LLEventPump. post_to(command, ...)
+-- engages LLLeapListener operations such as listening on a specified other
+-- LLEventPump, etc.
+local reply, command = LL.get_event_pumps()
+-- Dict of features added to the LEAP protocol since baseline implementation.
+-- Before engaging a new feature that might break an older viewer, we can
+-- check for the presence of that feature key. This table is solely about the
+-- LEAP protocol itself, the way we communicate with the viewer. To discover
+-- whether a given listener exists, or supports a particular operation, use
+-- command's "getAPI" operation.
+-- For Lua, command's "getFeatures" operation suffices?
+-- leap._features = {}
+
+-- Each outstanding request() or generate() call has a corresponding
+-- WaitForReqid object (later in this module) to handle the
+-- response(s). If an incoming event contains an echoed ["reqid"] key,
+-- we can look up the appropriate WaitForReqid object more efficiently
+-- in a dict than by tossing such objects into the usual waitfors list.
+-- Note: the ["reqid"] must be unique, otherwise we could end up
+-- replacing an earlier WaitForReqid object in pending with a
+-- later one. That means that no incoming event will ever be given to
+-- the old WaitForReqid object. Any coroutine waiting on the discarded
+-- WaitForReqid object would therefore wait forever.
+-- pending is NOT a weak table because the caller of request() or generate()
+-- never sees the WaitForReqid object. pending holds the only reference, so
+-- it should NOT be garbage-collected.
+local pending = {}
+-- Our consumer will instantiate some number of WaitFor subclass objects.
+-- As these are traversed in descending priority order, we must keep
+-- them in a list.
+-- Anyone who instantiates a WaitFor subclass object should retain a reference
+-- to it. Once the consuming script drops the reference, allow Lua to
+-- garbage-collect the WaitFor despite its entry in waitfors.
+local weak_values = {__mode='v'}
+local waitfors = setmetatable({}, weak_values)
+-- It has been suggested that we should use UUIDs as ["reqid"] values,
+-- since UUIDs are guaranteed unique. However, as the "namespace" for
+-- ["reqid"] values is our very own reply pump, we can get away with
+-- an integer.
+leap._reqid = 0
+-- break leap.process() loop
+leap._done = false
+
+-- get the name of the reply pump
+function leap.replypump()
+ return reply
+end
+
+-- get the name of the command pump
+function leap.cmdpump()
+ return command
+end
+
+-- Fire and forget. Send the specified request LLSD, expecting no reply.
+-- In fact, should the request produce an eventual reply, it will be
+-- treated as an unsolicited event.
+--
+-- See also request(), generate().
+function leap.send(pump, data, reqid)
+ local data = data
+ if type(data) == 'table' then
+ data = table.clone(data)
+ data['reply'] = reply
+ if reqid ~= nil then
+ data['reqid'] = reqid
+ end
+ end
+ dbg('leap.send(%s, %s) calling post_on()', pump, data)
+ LL.post_on(pump, data)
+end
+
+-- common setup code shared by request() and generate()
+local function requestSetup(pump, data)
+ -- invent a new, unique reqid
+ leap._reqid += 1
+ local reqid = leap._reqid
+ -- Instantiate a new WaitForReqid object. The priority is irrelevant
+ -- because, unlike the WaitFor base class, WaitForReqid does not
+ -- self-register on our waitfors list. Instead, capture the new
+ -- WaitForReqid object in pending so dispatch() can find it.
+ local waitfor = leap.WaitForReqid(reqid)
+ pending[reqid] = waitfor
+ -- Pass reqid to send() to stamp it into (a copy of) the request data.
+ dbg('requestSetup(%s, %s) storing %s', pump, data, waitfor.name)
+ leap.send(pump, data, reqid)
+ return reqid, waitfor
+end
+
+-- Send the specified request LLSD, expecting exactly one reply. Block
+-- the calling coroutine until we receive that reply.
+--
+-- Every request() (or generate()) LLSD block we send will get stamped
+-- with a distinct ["reqid"] value. The requested event API must echo the
+-- same ["reqid"] field in each reply associated with that request. This way
+-- we can correctly dispatch interleaved replies from different requests.
+--
+-- If the desired event API doesn't support the ["reqid"] echo convention,
+-- you should use send() instead -- since request() or generate() would
+-- wait forever for a reply stamped with that ["reqid"] -- and intercept
+-- any replies using WaitFor.
+--
+-- Unless the request data already contains a ["reply"] key, we insert
+-- reply=self.replypump to try to ensure that the expected reply will be
+-- returned over the socket.
+--
+-- See also send(), generate().
+function leap.request(pump, data)
+ local reqid, waitfor = requestSetup(pump, data)
+ dbg('leap.request(%s, %s) about to wait on %s', pump, data, tostring(waitfor))
+ local ok, response = pcall(waitfor.wait, waitfor)
+ dbg('leap.request(%s, %s) got %s: %s', pump, data, ok, response)
+ -- kill off temporary WaitForReqid object, even if error
+ pending[reqid] = nil
+ if not ok then
+ error(response)
+ elseif response.error then
+ error(response.error)
+ else
+ return response
+ end
+end
+
+-- Send the specified request LLSD, expecting an arbitrary number of replies.
+-- Each one is returned on request.
+--
+-- Usage:
+-- sequence = leap.generate(pump, data)
+-- repeat
+-- response = sequence.next()
+-- until last(response)
+-- (last() means whatever test the caller wants to perform on response)
+-- sequence.done()
+--
+-- See request() remarks about ["reqid"].
+--
+-- Note: this seems like a prime use case for Lua coroutines. But in a script
+-- using fibers.lua, a "wild" coroutine confuses the fiber scheduler. If
+-- generate() were itself a coroutine, it would call WaitForReqid:wait(),
+-- which would yield -- thereby resuming generate() WITHOUT waiting.
+function leap.generate(pump, data, checklast)
+ -- Invent a new, unique reqid. Arrange to handle incoming events
+ -- bearing that reqid. Stamp the outbound request with that reqid, and
+ -- send it.
+ local reqid, waitfor = requestSetup(pump, data)
+ return {
+ next = function()
+ dbg('leap.generate(%s).next() about to wait on %s', reqid, tostring(waitfor))
+ local ok, response = pcall(waitfor.wait, waitfor)
+ dbg('leap.generate(%s).next() got %s: %s', reqid, ok, response)
+ if not ok then
+ error(response)
+ elseif response.error then
+ error(response.error)
+ else
+ return response
+ end
+ end,
+ done = function()
+ -- cleanup consists of removing our WaitForReqid from pending
+ pending[reqid] = nil
+ end
+ }
+end
+
+-- Send the specified request LLSD, expecting an immediate reply followed by
+-- an arbitrary number of subsequent replies with the same reqid. Block the
+-- calling coroutine until the first (immediate) reply, but launch a separate
+-- fiber on which to call the passed callback with later replies.
+--
+-- Once the callback returns true, the background fiber terminates.
+function leap.eventstream(pump, data, callback)
+ local reqid, waitfor = requestSetup(pump, data)
+ local response = waitfor:wait()
+ if response.error then
+ -- clean up our WaitForReqid
+ waitfor:close()
+ error(response.error)
+ end
+ -- No error, so far so good:
+ -- call the callback with the first response just in case
+ dbg('leap.eventstream(%s): first callback', reqid)
+ local ok, done = pcall(callback, response)
+ dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done)
+ if not ok then
+ -- clean up our WaitForReqid
+ waitfor:close()
+ error(done)
+ end
+ if done then
+ return response
+ end
+ -- callback didn't throw an error, and didn't say stop,
+ -- so set up to handle subsequent events
+ -- TODO: distinguish "daemon" fibers that can be terminated even if waiting
+ fiber.launch(
+ pump,
+ function ()
+ local ok, done
+ local nth = 1
+ repeat
+ event = waitfor:wait()
+ if not event then
+ -- wait() returns nil once the queue is closed (e.g. cancelreq())
+ ok, done = true, true
+ else
+ nth += 1
+ dbg('leap.eventstream(%s): callback %d', reqid, nth)
+ ok, done = pcall(callback, event)
+ dbg('leap.eventstream(%s) got %s, %s', reqid, ok, done)
+ end
+ -- not ok means callback threw an error (caught as 'done')
+ -- done means callback succeeded but wants to stop
+ until (not ok) or done
+ -- once we break this loop, clean up our WaitForReqid
+ waitfor:close()
+ if not ok then
+ -- can't reflect the error back to our caller
+ LL.print_warning(fiber.get_name() .. ': ' .. done)
+ end
+ end)
+ return response
+end
+
+-- we might want to clean up after leap.eventstream() even if the callback has
+-- not yet returned true
+function leap.cancelreq(reqid)
+ dbg('cancelreq(%s)', reqid)
+ local waitfor = pending[reqid]
+ if waitfor ~= nil then
+ -- close() removes the pending entry and also closes the queue,
+ -- breaking the background fiber's wait loop.
+ dbg('cancelreq(%s) canceling %s', reqid, waitfor.name)
+ waitfor:close()
+ end
+end
+
+local function cleanup(message)
+ -- We're done: clean up all pending coroutines.
+ -- Iterate over copies of the pending and waitfors tables, since the
+ -- close() operation modifies the real tables.
+ for i, waitfor in pairs(table.clone(pending)) do
+ waitfor:close()
+ end
+ for i, waitfor in pairs(table.clone(waitfors)) do
+ waitfor:close()
+ end
+end
+
+-- Handle an incoming (pump, data) event with no recognizable ['reqid']
+local function unsolicited(pump, data)
+ -- we maintain waitfors in descending priority order, so the first waitfor
+ -- to claim this event is the one with the highest priority
+ for i, waitfor in pairs(waitfors) do
+ dbg('unsolicited() checking %s', waitfor.name)
+ if waitfor:handle(pump, data) then
+ return
+ end
+ end
+ LL.print_debug(string.format('unsolicited(%s, %s) discarding unclaimed event',
+ pump, inspect(data)))
+end
+
+-- Route incoming (pump, data) event to the appropriate waiting coroutine.
+local function dispatch(pump, data)
+ local reqid = data['reqid']
+ -- if the response has no 'reqid', it's not from request() or generate()
+ if reqid == nil then
+-- dbg('dispatch() found no reqid; calling unsolicited(%s, %s)', pump, data)
+ return unsolicited(pump, data)
+ end
+ -- have reqid; do we have a WaitForReqid?
+ local waitfor = pending[reqid]
+ if waitfor == nil then
+-- dbg('dispatch() found no WaitForReqid(%s); calling unsolicited(%s, %s)', reqid, pump, data)
+ return unsolicited(pump, data)
+ end
+ -- found the right WaitForReqid object, let it handle the event
+-- dbg('dispatch() calling %s.handle(%s, %s)', waitfor.name, pump, data)
+ waitfor:handle(pump, data)
+end
+
+-- We configure fiber.set_idle() function. fiber.yield() calls the configured
+-- idle callback whenever there are waiting fibers but no ready fibers. In
+-- our case, that means it's time to fetch another incoming viewer event.
+fiber.set_idle(function ()
+ -- If someone has called leap.done(), then tell fiber.yield() to break loop.
+ if leap._done then
+ cleanup('done')
+ return 'done'
+ end
+ dbg('leap.idle() calling get_event_next()')
+ local ok, pump, data = pcall(LL.get_event_next)
+ dbg('leap.idle() got %s: %s, %s', ok, pump, data)
+ -- ok false means get_event_next() raised a Lua error, pump is message
+ if not ok then
+ cleanup(pump)
+ error(pump)
+ end
+ -- data nil means get_event_next() returned (pump, LLSD()) to indicate done
+ if not data then
+ cleanup('end')
+ return 'end'
+ end
+ -- got a real pump, data pair
+ dispatch(pump, data)
+ -- return to fiber.yield(): any incoming message might result in one or
+ -- more fibers becoming ready
+end)
+
+function leap.done()
+ leap._done = true
+end
+
+-- called by WaitFor.enable()
+local function registerWaitFor(waitfor)
+ table.insert(waitfors, waitfor)
+ -- keep waitfors sorted in descending order of specified priority
+ table.sort(waitfors,
+ function (lhs, rhs) return lhs.priority > rhs.priority end)
+end
+
+-- called by WaitFor.disable()
+local function unregisterWaitFor(waitfor)
+ local i = table.find(waitfors, waitfor)
+ if i ~= nil then
+ waitfors[i] = nil
+ end
+end
+
+-- ******************************************************************************
+-- WaitFor and friends
+-- ******************************************************************************
+
+-- An unsolicited event is handled by the highest-priority WaitFor subclass
+-- object willing to accept it. If no such object is found, the unsolicited
+-- event is discarded.
+--
+-- * First, instantiate a WaitFor subclass object to register its interest in
+-- some incoming event(s). WaitFor instances are self-registering; merely
+-- instantiating the object suffices.
+-- * Any coroutine may call a given WaitFor object's wait() method. This blocks
+-- the calling coroutine until a suitable event arrives.
+-- * WaitFor's constructor accepts a float priority. Every incoming event
+-- (other than those claimed by request() or generate()) is passed to each
+-- extant WaitFor.filter() method in descending priority order. The first
+-- such filter() to return nontrivial data claims that event.
+-- * At that point, the blocked wait() call on that WaitFor object returns the
+-- item returned by filter().
+-- * WaitFor contains a queue. Multiple arriving events claimed by that WaitFor
+-- object's filter() method are added to the queue. Naturally, until the
+-- queue is empty, calling wait() immediately returns the front entry.
+--
+-- It's reasonable to instantiate a WaitFor subclass whose filter() method
+-- unconditionally returns the incoming event, and whose priority places it
+-- last in the list. This object will enqueue every unsolicited event left
+-- unclaimed by other WaitFor subclass objects.
+--
+-- It's not strictly necessary to associate a WaitFor object with exactly one
+-- coroutine. You might have multiple "worker" coroutines drawing from the same
+-- WaitFor object, useful if the work being done per event might itself involve
+-- "blocking" operations. Or a given coroutine might sample a number of WaitFor
+-- objects in round-robin fashion... etc. etc. Nonetheless, it's
+-- straightforward to designate one coroutine for each WaitFor object.
+
+-- --------------------------------- WaitFor ---------------------------------
+leap.WaitFor = { _id=0 }
+
+function leap.WaitFor.tostring(self)
+ -- Lua (sub)classes have no name; can't prefix with that
+ return self.name
+end
+
+function leap.WaitFor:new(priority, name)
+ local obj = setmetatable({__tostring=leap.WaitFor.tostring}, self)
+ self.__index = self
+
+ obj.priority = priority
+ if name then
+ obj.name = name
+ else
+ self._id += 1
+ obj.name = 'WaitFor' .. self._id
+ end
+ obj._queue = ErrorQueue()
+ obj._registered = false
+ -- if no priority, then don't enable() - remember 0 is truthy
+ if priority then
+ obj:enable()
+ end
+
+ return obj
+end
+
+util.classctor(leap.WaitFor)
+
+-- Re-enable a disable()d WaitFor object. New WaitFor objects are
+-- enable()d by default.
+function leap.WaitFor:enable()
+ if not self._registered then
+ registerWaitFor(self)
+ self._registered = true
+ end
+end
+
+-- Disable an enable()d WaitFor object.
+function leap.WaitFor:disable()
+ if self._registered then
+ unregisterWaitFor(self)
+ self._registered = false
+ end
+end
+
+-- Block the calling coroutine until a suitable unsolicited event (one
+-- for which filter() returns the event) arrives.
+function leap.WaitFor:wait()
+ dbg('%s about to wait', self.name)
+ local item = self._queue:Dequeue()
+ dbg('%s got %s', self.name, item)
+ return item
+end
+
+-- Override filter() to examine the incoming event in whatever way
+-- makes sense.
+--
+-- Return nil to ignore this event.
+--
+-- To claim the event, return the item you want placed in the queue.
+-- Typically you'd write:
+-- return data
+-- or perhaps
+-- return {pump=pump, data=data}
+-- or some variation.
+function leap.WaitFor:filter(pump, data)
+ error('You must override the WaitFor.filter() method')
+end
+
+-- called by unsolicited() for each WaitFor in waitfors
+function leap.WaitFor:handle(pump, data)
+ local item = self:filter(pump, data)
+ dbg('%s.filter() returned %s', self.name, item)
+ -- if this item doesn't pass the filter, we're not interested
+ if not item then
+ return false
+ end
+ -- okay, filter() claims this event
+ self:process(item)
+ return true
+end
+
+-- called by WaitFor:handle() for an accepted event
+function leap.WaitFor:process(item)
+ self._queue:Enqueue(item)
+end
+
+-- called by cleanup() at end
+function leap.WaitFor:close()
+ self:disable()
+ self._queue:close()
+end
+
+-- called by leap.process() when get_event_next() raises an error
+function leap.WaitFor:exception(message)
+ LL.print_warning(self.name .. ' error: ' .. message)
+ self._queue:Error(message)
+end
+
+-- ------------------------------ WaitForReqid -------------------------------
+leap.WaitForReqid = leap.WaitFor()
+
+function leap.WaitForReqid:new(reqid)
+ -- priority is meaningless, since this object won't be added to the
+ -- priority-sorted waitfors list. Use the reqid as the debugging name
+ -- string.
+ local obj = leap.WaitFor(nil, 'WaitForReqid(' .. reqid .. ')')
+ setmetatable(obj, self)
+ self.__index = self
+
+ obj.reqid = reqid
+
+ return obj
+end
+
+util.classctor(leap.WaitForReqid)
+
+function leap.WaitForReqid:filter(pump, data)
+ -- Because we expect to directly look up the WaitForReqid object of
+ -- interest based on the incoming ["reqid"] value, it's not necessary
+ -- to test the event again. Accept every such event.
+ return data
+end
+
+function leap.WaitForReqid:close()
+ -- remove this entry from pending table
+ pending[self.reqid] = nil
+ self._queue:close()
+end
+
+return leap
diff --git a/indra/newview/scripts/lua/require/login.lua b/indra/newview/scripts/lua/require/login.lua
new file mode 100644
index 0000000000..37c9093a21
--- /dev/null
+++ b/indra/newview/scripts/lua/require/login.lua
@@ -0,0 +1,42 @@
+local leap = require 'leap'
+local startup = require 'startup'
+local mapargs = require 'mapargs'
+
+local login = {}
+
+local function ensure_login_state(op)
+ -- no point trying to login until the viewer is ready
+ startup.wait('STATE_LOGIN_WAIT')
+ -- Once we've actually started login, LLPanelLogin is destroyed, and so is
+ -- its "LLPanelLogin" listener. At that point,
+ -- leap.request("LLPanelLogin", ...) will hang indefinitely because no one
+ -- is listening on that LLEventPump any more. Intercept that case and
+ -- produce a sensible error.
+ local state = startup.state()
+ if startup.before('STATE_LOGIN_WAIT', state) then
+ error(`Can't engage login operation {op} once we've reached state {state}`, 2)
+ end
+end
+
+local function fullgrid(grid)
+ if string.find(grid, '.', 1, true) then
+ return grid
+ else
+ return `util.{grid}.secondlife.com`
+ end
+end
+
+function login.login(...)
+ ensure_login_state('login')
+ local args = mapargs('username,grid,slurl', ...)
+ args.op = 'login'
+ args.grid = fullgrid(args.grid)
+ return leap.request('LLPanelLogin', args)
+end
+
+function login.savedLogins(grid)
+ ensure_login_state('savedLogins')
+ return leap.request('LLPanelLogin', {op='savedLogins', grid=fullgrid(grid)})['logins']
+end
+
+return login
diff --git a/indra/newview/scripts/lua/require/logout.lua b/indra/newview/scripts/lua/require/logout.lua
new file mode 100644
index 0000000000..63dcd7f01f
--- /dev/null
+++ b/indra/newview/scripts/lua/require/logout.lua
@@ -0,0 +1,7 @@
+local leap = require 'leap'
+
+local function logout()
+ leap.send('LLAppViewer', {op='userQuit'});
+end
+
+return logout
diff --git a/indra/newview/scripts/lua/require/mapargs.lua b/indra/newview/scripts/lua/require/mapargs.lua
new file mode 100644
index 0000000000..45f5a9c556
--- /dev/null
+++ b/indra/newview/scripts/lua/require/mapargs.lua
@@ -0,0 +1,73 @@
+-- Allow a calling function to be passed a mix of positional arguments with
+-- keyword arguments. Reference them as fields of a table.
+-- Don't use this for a function that can accept a single table argument.
+-- mapargs() assumes that a single table argument means its caller was called
+-- with f{table constructor} syntax, and maps that table to the specified names.
+-- Usage:
+-- function f(...)
+-- local a = mapargs({'a1', 'a2', 'a3'}, ...)
+-- ... a.a1 ... etc.
+-- end
+-- f(10, 20, 30) -- a.a1 == 10, a.a2 == 20, a.a3 == 30
+-- f{10, 20, 30} -- a.a1 == 10, a.a2 == 20, a.a3 == 30
+-- f{a3=300, a1=100} -- a.a1 == 100, a.a2 == nil, a.a3 == 300
+-- f{1, a3=3} -- a.a1 == 1, a.a2 == nil, a.a3 == 3
+-- f{a3=3, 1} -- a.a1 == 1, a.a2 == nil, a.a3 == 3
+local function mapargs(names, ...)
+ local args = table.pack(...)
+ local posargs = {}
+ local keyargs = {}
+ -- For a mixed table, no Lua operation will reliably tell you how many
+ -- array items it contains, if there are any holes. Track that by hand.
+ -- We must be able to handle f(1, nil, 3) calls.
+ local maxpos = 0
+
+ -- For convenience, allow passing 'names' as a string 'n0,n1,...'
+ if type(names) == 'string' then
+ names = string.split(names, ',')
+ end
+
+ if not (args.n == 1 and type(args[1]) == 'table') then
+ -- If caller passes more than one argument, or if the first argument
+ -- is not a table, then it's classic positional function-call syntax:
+ -- f(first, second, etc.). In that case we need not bother teasing
+ -- apart positional from keyword arguments.
+ posargs = args
+ maxpos = args.n
+ else
+ -- Single table argument implies f{mixed} syntax.
+ -- Tease apart positional arguments from keyword arguments.
+ for k, v in pairs(args[1]) do
+ if type(k) == 'number' then
+ posargs[k] = v
+ maxpos = math.max(maxpos, k)
+ else
+ if table.find(names, k) == nil then
+ error('unknown keyword argument ' .. tostring(k))
+ end
+ keyargs[k] = v
+ end
+ end
+ end
+
+ -- keyargs already has keyword arguments in place, just fill in positionals
+ args = keyargs
+ -- Don't exceed the number of parameter names. Loop explicitly over every
+ -- index value instead of using ipairs() so we can support holes (nils) in
+ -- posargs.
+ for i = 1, math.min(#names, maxpos) do
+ if posargs[i] ~= nil then
+ -- As in Python, make it illegal to pass an argument both positionally
+ -- and by keyword. This implementation permits func(17, first=nil), a
+ -- corner case about which I don't particularly care.
+ if args[names[i]] ~= nil then
+ error(string.format('parameter %s passed both positionally and by keyword',
+ tostring(names[i])))
+ end
+ args[names[i]] = posargs[i]
+ end
+ end
+ return args
+end
+
+return mapargs
diff --git a/indra/newview/scripts/lua/require/printf.lua b/indra/newview/scripts/lua/require/printf.lua
new file mode 100644
index 0000000000..e84b2024df
--- /dev/null
+++ b/indra/newview/scripts/lua/require/printf.lua
@@ -0,0 +1,19 @@
+-- printf(...) is short for print(string.format(...))
+
+local inspect = require 'inspect'
+
+local function printf(format, ...)
+ -- string.format() only handles numbers and strings.
+ -- Convert anything else to string using the inspect module.
+ local args = {}
+ for _, arg in pairs(table.pack(...)) do
+ if type(arg) == 'number' or type(arg) == 'string' then
+ table.insert(args, arg)
+ else
+ table.insert(args, inspect(arg))
+ end
+ end
+ print(string.format(format, table.unpack(args)))
+end
+
+return printf
diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua
new file mode 100644
index 0000000000..5301d7838c
--- /dev/null
+++ b/indra/newview/scripts/lua/require/result_view.lua
@@ -0,0 +1,98 @@
+local leap = require 'leap'
+
+-- metatable for every result_view() table
+local mt = {
+ __len = function(self)
+ return self.length
+ end,
+ __index = function(self, i)
+ -- right away, convert to 0-relative indexing
+ i -= 1
+ -- can we find this index within the current slice?
+ local reli = i - self.start
+ if 0 <= reli and reli < #self.slice then
+ -- Lua 1-relative indexing
+ return self.slice[reli + 1]
+ end
+ -- is this index outside the overall result set?
+ if not (0 <= i and i < self.length) then
+ return nil
+ end
+ -- fetch a new slice starting at i, using provided fetch()
+ local start
+ self.slice, start = self.fetch(self.key, i)
+ -- It's possible that caller-provided fetch() function forgot
+ -- to return the adjusted start index of the new slice. In
+ -- Lua, 0 tests as true, so if fetch() returned (slice, 0),
+ -- we'll duly reset self.start to 0. Otherwise, assume the
+ -- requested index was not adjusted: that the returned slice
+ -- really does start at i.
+ self.start = start or i
+ -- Hopefully this slice contains the desired i.
+ -- Back to 1-relative indexing.
+ return self.slice[i - self.start + 1]
+ end,
+ -- We purposely avoid putting any array entries (int keys) into
+ -- our table so that access to any int key will always call our
+ -- __index() metamethod. Moreover, we want any table iteration to
+ -- call __index(table, i) however many times; we do NOT want it to
+ -- retrieve key, length, start, slice.
+ -- So turn 'for k, v in result' into 'for k, v in ipairs(result)'.
+ __iter = ipairs,
+ -- This result set provides read-only access.
+ -- We do not support pushing updates to individual items back to
+ -- C++; for the intended use cases, that makes no sense.
+ __newindex = function(self, i, value)
+ error("result_view is a read-only data structure", 2)
+ end
+}
+
+-- result_view(key_length, fetch) returns a table which stores only a slice
+-- of a result set plus some control values, yet presents read-only virtual
+-- access to the entire result set.
+-- key_length: {result set key, total result set length}
+-- fetch: function(key, start) that returns (slice, adjusted start)
+local result_view = setmetatable(
+ {
+ -- generic fetch() function
+ fetch = function(key, start)
+ local fetched = leap.request(
+ 'LLInventory',
+ {op='getSlice', result=key, index=start})
+ return fetched.slice, fetched.start
+ end,
+ -- generic close() function accepting variadic result-set keys
+ close = function(...)
+ local keys = table.pack(...)
+ -- table.pack() produces a table with an array entry for every
+ -- parameter, PLUS an 'n' key with the count. Unfortunately that
+ -- 'n' key bollixes our conversion to LLSD, which requires either
+ -- all int keys (for an array) or all string keys (for a map).
+ keys.n = nil
+ leap.send('LLInventory', {op='closeResult', result=keys})
+ end
+ },
+ {
+ -- result_view(key_length, fetch) calls this
+ __call = function(class, key_length, fetch)
+ return setmetatable(
+ {
+ key=key_length[1],
+ length=key_length[2],
+ -- C++ result sets use 0-based indexing, so internally we do too
+ start=0,
+ -- start with a dummy array with length 0
+ slice={},
+ -- if caller didn't pass fetch() function, use generic
+ fetch=fetch or class.fetch,
+ -- returned view:close() will close result set with passed key
+ close=function(self) class.close(key_length[1]) end
+ },
+ -- use our special metatable
+ mt
+ )
+ end
+ }
+)
+
+return result_view
diff --git a/indra/newview/scripts/lua/require/startup.lua b/indra/newview/scripts/lua/require/startup.lua
new file mode 100644
index 0000000000..c3040f94b8
--- /dev/null
+++ b/indra/newview/scripts/lua/require/startup.lua
@@ -0,0 +1,100 @@
+-- query, wait for or mandate a particular viewer startup state
+
+-- During startup, the viewer steps through a sequence of numbered (and named)
+-- states. This can be used to detect when, for instance, the login screen is
+-- displayed, or when the viewer has finished logging in and is fully
+-- in-world.
+
+local fiber = require 'fiber'
+local leap = require 'leap'
+local inspect = require 'inspect'
+local function dbg(...) end
+-- local dbg = require 'printf'
+
+-- ---------------------------------------------------------------------------
+local startup = {}
+
+-- Get the list of startup states from the viewer.
+local bynum = leap.request('LLStartUp', {op='getStateTable'})['table']
+
+local byname = setmetatable(
+ {},
+ -- set metatable to throw an error if you look up invalid state name
+ {__index=function(t, k)
+ local v = rawget(t, k)
+ if v then
+ return v
+ end
+ error(string.format('startup module passed invalid state %q', k), 2)
+ end})
+
+-- derive byname as a lookup table to find the 0-based index for a given name
+for i, name in pairs(bynum) do
+ -- the viewer's states are 0-based, not 1-based like Lua indexes
+ byname[name] = i - 1
+end
+-- dbg('startup states: %s', inspect(byname))
+
+-- specialize a WaitFor to track the viewer's startup state
+local startup_pump = 'StartupState'
+local waitfor = leap.WaitFor(0, startup_pump)
+function waitfor:filter(pump, data)
+ if pump == self.name then
+ return data
+ end
+end
+
+function waitfor:process(data)
+ -- keep updating startup._state for interested parties
+ startup._state = data.str
+ dbg('startup updating state to %q', data.str)
+ -- now pass data along to base-class method to queue
+ leap.WaitFor.process(self, data)
+end
+
+-- listen for StartupState events
+leap.request(leap.cmdpump(),
+ {op='listen', source=startup_pump, listener='startup.lua', tweak=true})
+-- poke LLStartUp to make sure we get an event
+leap.send('LLStartUp', {op='postStartupState'})
+
+-- ---------------------------------------------------------------------------
+-- wait for response from postStartupState
+while not startup._state do
+ dbg('startup.state() waiting for first StartupState event')
+ waitfor:wait()
+end
+
+-- return a list of all known startup states
+function startup.list()
+ return bynum
+end
+
+-- report whether state with string name 'left' is before string name 'right'
+function startup.before(left, right)
+ return byname[left] < byname[right]
+end
+
+-- report the viewer's current startup state
+function startup.state()
+ return startup._state
+end
+
+-- error if script is called before specified state string name
+function startup.ensure(state)
+ if startup.before(startup.state(), state) then
+ -- tell error() to pretend this error was thrown by our caller
+ error('must not be called before startup state ' .. state, 2)
+ end
+end
+
+-- block calling fiber until viewer has reached state with specified string name
+function startup.wait(state)
+ dbg('startup.wait(%q)', state)
+ while startup.before(startup.state(), state) do
+ local item = waitfor:wait()
+ dbg('startup.wait(%q) sees %s', state, item)
+ end
+end
+
+return startup
diff --git a/indra/newview/scripts/lua/require/timers.lua b/indra/newview/scripts/lua/require/timers.lua
new file mode 100644
index 0000000000..ab1615ffbf
--- /dev/null
+++ b/indra/newview/scripts/lua/require/timers.lua
@@ -0,0 +1,122 @@
+-- Access to the viewer's time-delay facilities
+
+local leap = require 'leap'
+local util = require 'util'
+
+local timers = {}
+
+local function dbg(...) end
+-- local dbg = require 'printf'
+
+timers.Timer = {}
+
+-- delay: time in seconds until callback
+-- callback: 'wait', or function to call when timer fires (self:tick if nil)
+-- iterate: if non-nil, call callback repeatedly until it returns non-nil
+-- (ignored if 'wait')
+function timers.Timer:new(delay, callback, iterate)
+ local obj = setmetatable({}, self)
+ self.__index = self
+
+ if callback == 'wait' then
+ dbg('scheduleAfter(%d):', delay)
+ sequence = leap.generate('Timers', {op='scheduleAfter', after=delay})
+ -- ignore the immediate return
+ dbg('scheduleAfter(%d) -> %s', delay,
+ sequence.next())
+ -- this call is where we wait for real
+ dbg('next():')
+ dbg('next() -> %s',
+ sequence.next())
+ sequence.done()
+ return
+ end
+
+ callback = callback or function() obj:tick() end
+
+ local calls = 0
+ if iterate then
+ -- With iterative timers, beware of running a timer callback which
+ -- performs async actions lasting longer than the timer interval. The
+ -- lengthy callback suspends, allowing leap to retrieve the next
+ -- event, which is a timer tick. leap calls a new instance of the
+ -- callback, even though the previous callback call is still
+ -- suspended... etc. 'in_callback' defends against that recursive
+ -- case. Rather than re-enter the suspended callback, drop the
+ -- too-soon timer event. (We could count the too-soon timer events and
+ -- iterate calling the callback, but it's a bathtub problem: the
+ -- callback could end up getting farther and farther behind.)
+ local in_callback = false
+ obj.id = leap.eventstream(
+ 'Timers',
+ {op='scheduleEvery', every=delay},
+ function (event)
+ local reqid = event.reqid
+ calls += 1
+ if calls == 1 then
+ dbg('timer(%s) first callback', reqid)
+ -- discard the first (immediate) response: don't call callback
+ return nil
+ else
+ if in_callback then
+ dbg('dropping timer(%s) callback %d', reqid, calls)
+ else
+ dbg('timer(%s) callback %d', reqid, calls)
+ in_callback = true
+ local ret = callback(event)
+ in_callback = false
+ return ret
+ end
+ end
+ end
+ ).reqid
+ else -- (not iterate)
+ obj.id = leap.eventstream(
+ 'Timers',
+ {op='scheduleAfter', after=delay},
+ function (event)
+ calls += 1
+ -- Arrange to return nil the first time, true the second. This
+ -- callback is called immediately with the response to
+ -- 'scheduleAfter', and if we immediately returned true, we'd
+ -- be done, and the subsequent timer event would be discarded.
+ if calls == 1 then
+ -- Caller doesn't expect an immediate callback.
+ return nil
+ else
+ callback(event)
+ -- Since caller doesn't want to iterate, the value
+ -- returned by the callback is irrelevant: just stop after
+ -- this one and only call.
+ return true
+ end
+ end
+ ).reqid
+ end
+
+ return obj
+end
+
+util.classctor(timers.Timer)
+
+function timers.Timer:tick()
+ error('Pass a callback to Timer:new(), or override Timer:tick()')
+end
+
+function timers.Timer:cancel()
+ local ok = leap.request('Timers', {op='cancel', id=self.id}).ok
+ leap.cancelreq(self.id)
+ return ok
+end
+
+function timers.Timer:isRunning()
+ return leap.request('Timers', {op='isRunning', id=self.id}).running
+end
+
+-- returns (true, seconds left) for a live timer, else (false, 0)
+function timers.Timer:timeUntilCall()
+ local result = leap.request('Timers', {op='timeUntilCall', id=self.id})
+ return result.ok, result.remaining
+end
+
+return timers
diff --git a/indra/newview/scripts/lua/require/util.lua b/indra/newview/scripts/lua/require/util.lua
new file mode 100644
index 0000000000..40737a159a
--- /dev/null
+++ b/indra/newview/scripts/lua/require/util.lua
@@ -0,0 +1,114 @@
+-- utility functions, in alpha order
+
+local util = {}
+
+-- Allow MyClass(ctor args...) equivalent to MyClass:new(ctor args...)
+-- Usage:
+-- local MyClass = {}
+-- function MyClass:new(...)
+-- ...
+-- end
+-- ...
+-- util.classctor(MyClass)
+-- or if your constructor is named something other than MyClass:new(), e.g.
+-- MyClass:construct():
+-- util.classctor(MyClass, MyClass.construct)
+-- return MyClass
+function util.classctor(class, ctor)
+ -- set class's __call metamethod to the specified constructor function
+ -- (class.new if not specified)
+ util.setmetamethods{class, __call=(ctor or class.new)}
+end
+
+-- check if array-like table contains certain value
+function util.contains(t, v)
+ return table.find(t, v) ~= nil
+end
+
+-- reliable count of the number of entries in table t
+-- (since #t is unreliable)
+function util.count(t)
+ local count = 0
+ for _ in pairs(t) do
+ count += 1
+ end
+ return count
+end
+
+-- cheap test whether table t is empty
+function util.empty(t)
+ return not next(t)
+end
+
+-- recursive table equality
+function util.equal(t1, t2)
+ if not (type(t1) == 'table' and type(t2) == 'table') then
+ return t1 == t2
+ end
+ -- both t1 and t2 are tables: get modifiable copy of t2
+ local temp = table.clone(t2)
+ for k, v in pairs(t1) do
+ -- if any key in t1 doesn't have same value in t2, not equal
+ if not util.equal(v, temp[k]) then
+ return false
+ end
+ -- temp[k] == t1[k], delete temp[k]
+ temp[k] = nil
+ end
+ -- All keys in t1 have equal values in t2; t2 == t1 if there are no extra keys in t2
+ return util.empty(temp)
+end
+
+-- Find or create the metatable for a specified table (a new empty table if
+-- omitted), and to that metatable assign the specified keys.
+-- Setting multiple keys at once is more efficient than a function to set only
+-- one at a time, e.g. setametamethod().
+-- t = util.setmetamethods{__index=readfunc, __len=lenfunc}
+-- returns a new table with specified metamethods __index, __len
+-- util.setmetamethods{t, __call=action}
+-- finds or creates the metatable for existing table t and sets __call
+-- util.setmetamethods{table=t, __call=action}
+-- same as util.setmetamethods{t, __call=action}
+function util.setmetamethods(specs)
+ -- first determine the target table
+ assert(not (specs.table and specs[1]),
+ "Pass setmetamethods table either as positional or table=, not both")
+ local t = specs.table or specs[1] or {}
+ -- remove both ways of specifying table, leaving only the metamethods
+ specs.table = nil
+ specs[1] = nil
+ local mt = getmetatable(t)
+ if not mt then
+ -- t doesn't already have a metatable: just set specs
+ setmetatable(t, specs)
+ else
+ -- t already has a metatable: copy specs into it
+ local key, value
+ for key, value in pairs(specs) do
+ mt[key] = value
+ end
+ end
+ -- having set or enriched t's metatable, return t
+ return t
+end
+
+-- On the passed module (i.e. table), set an __index metamethod such that
+-- referencing module.submodule lazily requires(path/submodule).
+-- The loaded submodule is cached in the module table so it need not be passed
+-- to require() again.
+-- 'path', like any require() string, can be relative to LuaRequirePath.
+-- Returns the enriched module, permitting e.g.
+-- mymod = util.submoduledir({}, 'mymod')
+function util.submoduledir(module, path)
+ return util.setmetamethods{
+ module,
+ __index=function(t, key)
+ local mod = require(`{path}/{key}`)
+ -- cache the submodule
+ t[key] = mod
+ return mod
+ end
+ }
+end
+
+return util
diff --git a/indra/newview/scripts/lua/test_LLAppearance.lua b/indra/newview/scripts/lua/test_LLAppearance.lua
new file mode 100644
index 0000000000..a97ec4e0ca
--- /dev/null
+++ b/indra/newview/scripts/lua/test_LLAppearance.lua
@@ -0,0 +1,114 @@
+local LLAppearance = require 'LLAppearance'
+local startup = require 'startup'
+local inspect = require 'inspect'
+local UI = require 'UI'
+
+local SHOW_OUTFITS = true
+local SELECTED_OUTFIT_ID = {}
+local DATA_MAP = {}
+
+local wearables_lbl = 'Show wearables'
+local outfits_lbl = 'Show outfits'
+local replace_cof_lbl = 'Replace COF'
+local add_cof_lbl = 'Add to COF'
+local outfits_title = 'Outfits'
+local wear_lbl = 'Wear item'
+local detach_lbl = 'Detach item'
+
+local flt = UI.Floater(
+ "luafloater_outfits_list.xml",
+ {outfits_list = {"double_click"}})
+
+function get_selected_id()
+ return flt:request({action="get_selected_id", ctrl_name='outfits_list'}).value
+end
+
+function populate_list()
+ if SHOW_OUTFITS then
+ DATA_MAP = LLAppearance.getOutfitsList()
+ else
+ DATA_MAP = LLAppearance.getOutfitItems(SELECTED_OUTFIT_ID)
+ end
+
+ local action_data = {}
+ action_data.action = "add_list_element"
+ action_data.ctrl_name = "outfits_list"
+ local outfits = {}
+ for uuid, info in pairs(DATA_MAP) do
+ name = {}
+ if SHOW_OUTFITS then
+ name = info
+ else
+ name = info.name
+ end
+ table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}})
+ end
+ action_data.value = outfits
+ flt:post(action_data)
+end
+
+function set_label(btn_name, value)
+ flt:post({action="set_label", ctrl_name=btn_name, value=value})
+end
+
+function set_enabled(btn_name, value)
+ flt:post({action="set_enabled", ctrl_name=btn_name, value=value})
+end
+
+function update_labels()
+ if SHOW_OUTFITS then
+ set_label('select_btn', wearables_lbl)
+ set_label('replace_btn', replace_cof_lbl)
+ set_label('add_btn', add_cof_lbl)
+
+ set_enabled('select_btn', false)
+ flt:post({action="set_title", value=outfits_title})
+ else
+ set_label('select_btn', outfits_lbl)
+ set_label('replace_btn', wear_lbl)
+ set_label('add_btn', detach_lbl)
+
+ set_enabled('select_btn', true)
+ flt:post({action="set_title", value=DATA_MAP[SELECTED_OUTFIT_ID]})
+ end
+
+ set_enabled('replace_btn', false)
+ set_enabled('add_btn', false)
+end
+
+function flt:post_build(event_data)
+ populate_list()
+end
+
+function flt:commit_replace_btn(event_data)
+ if SHOW_OUTFITS then
+ LLAppearance.wearOutfit(get_selected_id(), 'replace')
+ else
+ LLAppearance.wearItems(get_selected_id(), false)
+ end
+end
+
+function flt:commit_add_btn(event_data)
+ if SHOW_OUTFITS then
+ LLAppearance.wearOutfit(get_selected_id(), 'add')
+ else
+ LLAppearance.detachItems(get_selected_id())
+ end
+end
+
+function flt:commit_select_btn(event_data)
+ SHOW_OUTFITS = not SHOW_OUTFITS
+ SELECTED_OUTFIT_ID = get_selected_id()
+ update_labels()
+ self:post({action="clear_list", ctrl_name='outfits_list'})
+ populate_list()
+end
+
+function flt:commit_outfits_list(event_data)
+ set_enabled('replace_btn', true)
+ set_enabled('add_btn', true)
+ set_enabled('select_btn', true)
+end
+
+startup.wait('STATE_STARTED')
+flt:show()
diff --git a/indra/newview/scripts/lua/test_LLChat.lua b/indra/newview/scripts/lua/test_LLChat.lua
new file mode 100644
index 0000000000..3abaf28e42
--- /dev/null
+++ b/indra/newview/scripts/lua/test_LLChat.lua
@@ -0,0 +1,18 @@
+LLChat = require 'LLChat'
+
+function generateRandomWord(length)
+ local alphabet = "abcdefghijklmnopqrstuvwxyz"
+ local wordTable = {}
+ for i = 1, length do
+ local randomIndex = math.random(1, #alphabet)
+ table.insert(wordTable, alphabet:sub(randomIndex, randomIndex))
+ end
+ return table.concat(wordTable)
+end
+
+local msg = {'AI says:'}
+math.randomseed(os.time())
+for i = 1, math.random(1, 10) do
+ table.insert(msg, generateRandomWord(math.random(1, 8)))
+end
+LLChat.sendNearby(table.concat(msg, ' '))
diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua
new file mode 100644
index 0000000000..fa00b048b2
--- /dev/null
+++ b/indra/newview/scripts/lua/test_LLChatListener.lua
@@ -0,0 +1,44 @@
+local LLAgent = require 'LLAgent'
+local LLChat = require 'LLChat'
+local LLListener = require 'LLListener'
+local UI = require 'UI'
+
+-- Chat listener script allows to use the following commands in Nearby chat:
+-- open inventory -- open defined floater by name
+-- close inventory -- close defined floater by name
+-- closeall -- close all floaters
+-- stop -- close the script
+-- any other messages will be echoed.
+function openOrEcho(message)
+ local open_floater_name = string.match(message, "^open%s+(%w+)")
+ local close_floater_name = string.match(message, "^close%s+(%w+)")
+ if open_floater_name then
+ UI.showFloater(open_floater_name)
+ elseif close_floater_name then
+ UI.hideFloater(close_floater_name)
+ elseif message == 'closeall' then
+ UI.closeAllFloaters()
+ else
+ LLChat.sendNearby('Echo: ' .. message)
+ end
+end
+
+local listener = LLListener(LLChat.nearbyChatPump)
+local agent_id = LLAgent.getID()
+
+function listener:handleMessages(event_data)
+ -- ignore messages and commands from other avatars
+ if event_data.from_id ~= agent_id then
+ return true
+ elseif string.find(event_data.message, '[LUA]') then
+ return true
+ elseif event_data.message == 'stop' then
+ LLChat.sendNearby('Closing echo script.')
+ return false
+ else
+ openOrEcho(event_data.message)
+ end
+ return true
+end
+
+listener:start()
diff --git a/indra/newview/scripts/lua/test_LLFloaterAbout.lua b/indra/newview/scripts/lua/test_LLFloaterAbout.lua
new file mode 100644
index 0000000000..6bbf61982d
--- /dev/null
+++ b/indra/newview/scripts/lua/test_LLFloaterAbout.lua
@@ -0,0 +1,6 @@
+-- test LLFloaterAbout
+
+LLFloaterAbout = require('LLFloaterAbout')
+inspect = require('inspect')
+
+print(inspect(LLFloaterAbout.getInfo()))
diff --git a/indra/newview/scripts/lua/test_LLGesture.lua b/indra/newview/scripts/lua/test_LLGesture.lua
new file mode 100644
index 0000000000..1cce674565
--- /dev/null
+++ b/indra/newview/scripts/lua/test_LLGesture.lua
@@ -0,0 +1,26 @@
+-- exercise LLGesture API
+
+LLGesture = require 'LLGesture'
+inspect = require 'inspect'
+
+
+-- getActiveGestures() returns {<UUID>: {name, playing, trigger}}
+gestures_uuid = LLGesture.getActiveGestures()
+-- convert to {<name>: <uuid>}
+gestures = {}
+for uuid, info in pairs(gestures_uuid) do
+ gestures[info.name] = uuid
+end
+-- now run through the list
+for name, uuid in pairs(gestures) do
+ if name == 'afk' then
+ -- afk has a long timeout, and isn't interesting to look at
+ continue
+ end
+ print(name)
+ LLGesture.startGesture(uuid)
+ repeat
+ LL.sleep(1)
+ until not LLGesture.isGesturePlaying(uuid)
+end
+print('Done.')
diff --git a/indra/newview/scripts/lua/test_LLInventory.lua b/indra/newview/scripts/lua/test_LLInventory.lua
new file mode 100644
index 0000000000..de57484bcd
--- /dev/null
+++ b/indra/newview/scripts/lua/test_LLInventory.lua
@@ -0,0 +1,24 @@
+inspect = require 'inspect'
+LLInventory = require 'LLInventory'
+
+-- Get 'My Landmarks' folder id (you can see all folder types via LLInventory.getFolderTypeNames())
+my_landmarks_id = LLInventory.getBasicFolderID('landmark')
+-- Get 3 landmarks from the 'My Landmarks' folder (you can see all folder types via LLInventory.getAssetTypeNames())
+landmarks = LLInventory.collectDescendentsIf{folder_id=my_landmarks_id, type="landmark", limit=3}
+for _, landmark in pairs(landmarks.items) do
+ print(landmark.name)
+end
+
+-- Get 'Calling Cards' folder id
+calling_cards_id = LLInventory.getBasicFolderID('callcard')
+-- Get all items located directly in 'Calling Cards' folder
+calling_cards = LLInventory.getDirectDescendents(calling_cards_id).items
+
+-- Print a random calling card name from 'Calling Cards' folder
+-- (because getDirectDescendents().items is a Lua result set, selecting
+-- a random entry only fetches one slice containing that entry)
+math.randomseed(os.time())
+for i = 1, 5 do
+ pick = math.random(#calling_cards)
+ print(`Random calling card (#{pick} of {#calling_cards}): {calling_cards[pick].name}`)
+end
diff --git a/indra/newview/scripts/lua/test_animation.lua b/indra/newview/scripts/lua/test_animation.lua
new file mode 100644
index 0000000000..ae5eabe148
--- /dev/null
+++ b/indra/newview/scripts/lua/test_animation.lua
@@ -0,0 +1,32 @@
+LLInventory = require 'LLInventory'
+LLAgent = require 'LLAgent'
+
+-- Get 'Animations' folder id (you can see all folder types via LLInventory.getFolderTypeNames())
+animations_id = LLInventory.getBasicFolderID('animatn')
+-- Get animations from the 'Animation' folder (you can see all folder types via LLInventory.getAssetTypeNames())
+anims = LLInventory.collectDescendentsIf{folder_id=animations_id, type="animatn"}.items
+
+local anim_ids = {}
+for _, key in pairs(anims) do
+ table.insert(anim_ids, {id = key.id, name = key.name})
+end
+
+if #anim_ids == 0 then
+ print("No animations found")
+else
+ -- Start playing a random animation
+ math.randomseed(os.time())
+ local random_anim = anim_ids[math.random(#anim_ids)]
+ local anim_info = LLAgent.getAnimationInfo(random_anim.id)
+
+ print("Starting animation locally: " .. random_anim.name)
+ print("Loop: " .. tostring(anim_info.is_loop) .. " Joints: " .. anim_info.num_joints .. " Duration " .. tonumber(string.format("%.2f", anim_info.duration)))
+ LLAgent.playAnimation{item_id=random_anim.id}
+
+ -- Stop animation after 3 sec if it's looped or longer than 3 sec
+ if anim_info.is_loop or anim_info.duration > 3 then
+ LL.sleep(3)
+ print("Stop animation.")
+ LLAgent.stopAnimation(random_anim.id)
+ end
+end
diff --git a/indra/newview/scripts/lua/test_atexit.lua b/indra/newview/scripts/lua/test_atexit.lua
new file mode 100644
index 0000000000..6fbc0f3eb1
--- /dev/null
+++ b/indra/newview/scripts/lua/test_atexit.lua
@@ -0,0 +1,3 @@
+LL.atexit(function() print('Third') end)
+LL.atexit(function() print('Second') end)
+LL.atexit(function() print('First') end)
diff --git a/indra/newview/scripts/lua/test_autopilot.lua b/indra/newview/scripts/lua/test_autopilot.lua
new file mode 100644
index 0000000000..09c85c140a
--- /dev/null
+++ b/indra/newview/scripts/lua/test_autopilot.lua
@@ -0,0 +1,22 @@
+local LLAgent = require 'LLAgent'
+local LLListener = require 'LLListener'
+
+local pos = LLAgent.getGlobalPosition()
+pos[1]+=10 -- delta x
+pos[2]+=5 -- delta y
+LLAgent.requestStand()
+LLAgent.startAutoPilot{target_global=pos,allow_flying=false,stop_distance=1}
+
+local listener = LLListener(LLAgent.autoPilotPump)
+
+function listener:handleMessages(event_data)
+ if event_data.success then
+ print('Destination is reached')
+ LLAgent.requestSit()
+ else
+ print('Failed to reach destination')
+ end
+ return false
+end
+
+listener:start()
diff --git a/indra/newview/scripts/lua/test_callables.lua b/indra/newview/scripts/lua/test_callables.lua
new file mode 100644
index 0000000000..1bee062db8
--- /dev/null
+++ b/indra/newview/scripts/lua/test_callables.lua
@@ -0,0 +1,6 @@
+startup=require 'startup'
+UI=require 'UI'
+startup.wait('STATE_LOGIN_WAIT')
+for _, cbl in pairs(UI.callables()) do
+ print(`{cbl.name} ({cbl.access})`)
+end
diff --git a/indra/newview/scripts/lua/test_camera_control.lua b/indra/newview/scripts/lua/test_camera_control.lua
new file mode 100644
index 0000000000..7ac0986ee6
--- /dev/null
+++ b/indra/newview/scripts/lua/test_camera_control.lua
@@ -0,0 +1,49 @@
+local LLAgent = require 'LLAgent'
+local startup = require 'startup'
+local UI = require 'UI'
+
+local flt = UI.Floater('luafloater_camera_control.xml')
+
+function getValue(ctrl_name)
+ return flt:request({action="get_value", ctrl_name=ctrl_name}).value
+end
+
+function setValue(ctrl_name, value)
+ flt:post({action="set_value", ctrl_name=ctrl_name, value=value})
+end
+
+function flt:commit_update_btn(event_data)
+ lock_focus = getValue('lock_focus_ctrl')
+ lock_camera = getValue('lock_camera_ctrl')
+ local camera_pos = {getValue('cam_x'), getValue('cam_y'), getValue('cam_z')}
+ local focus_pos = {getValue('focus_x'), getValue('focus_y'), getValue('focus_z')}
+
+ LLAgent.setCamera{camera_pos=camera_pos, focus_pos=focus_pos,
+ focus_locked=lock_focus, camera_locked=lock_camera}
+
+ self:post({action="add_text", ctrl_name="events_editor",
+ value = {'Updating FollowCam params', 'camera_pos:', camera_pos, 'focus_pos:', focus_pos,
+ 'lock_focus:', lock_focus, 'lock_camera:', lock_camera}})
+end
+
+function flt:commit_agent_cam_btn(event_data)
+ agent_pos = LLAgent.getRegionPosition()
+ setValue('cam_x', math.floor(agent_pos[1]))
+ setValue('cam_y', math.floor(agent_pos[2]))
+ setValue('cam_z', math.floor(agent_pos[3]))
+end
+
+function flt:commit_agent_focus_btn(event_data)
+ agent_pos = LLAgent.getRegionPosition()
+ setValue('focus_x', math.floor(agent_pos[1]))
+ setValue('focus_y', math.floor(agent_pos[2]))
+ setValue('focus_z', math.floor(agent_pos[3]))
+end
+
+function flt:commit_reset_btn(event_data)
+ LLAgent.removeCamParams()
+ LLAgent.setFollowCamActive(false)
+end
+
+startup.wait('STATE_STARTED')
+flt:show()
diff --git a/indra/newview/scripts/lua/test_flycam.lua b/indra/newview/scripts/lua/test_flycam.lua
new file mode 100644
index 0000000000..05c3c37b93
--- /dev/null
+++ b/indra/newview/scripts/lua/test_flycam.lua
@@ -0,0 +1,38 @@
+-- Make camera fly around the subject avatar for a few seconds.
+
+local LLAgent = require 'LLAgent'
+local startup = require 'startup'
+local timers = require 'timers'
+
+local height = 2.0 -- meters
+local radius = 4.0 -- meters
+local speed = 1.0 -- meters/second along circle
+local start = os.clock()
+local stop = os.clock() + 30 -- seconds
+
+local function cameraPos(t)
+ local agent = LLAgent.getRegionPosition()
+ local radians = speed * t
+ return {
+ agent[1] + radius * math.cos(radians),
+ agent[2] + radius * math.sin(radians),
+ agent[3] + height
+ }
+end
+
+local function moveCamera()
+ if os.clock() < stop then
+ -- usual case
+ LLAgent.setCamera{ camera_pos=cameraPos(os.clock() - start), camera_locked=true }
+ return nil
+ else
+ -- last time
+ LLAgent.removeCamParams()
+ LLAgent.setFollowCamActive(false)
+ return true
+ end
+end
+
+startup.wait('STATE_STARTED')
+-- call moveCamera() repeatedly until it returns true
+local timer = timers.Timer(0.1, moveCamera, true)
diff --git a/indra/newview/scripts/lua/test_group_chat.lua b/indra/newview/scripts/lua/test_group_chat.lua
new file mode 100644
index 0000000000..373411c26c
--- /dev/null
+++ b/indra/newview/scripts/lua/test_group_chat.lua
@@ -0,0 +1,14 @@
+LLChat = require 'LLChat'
+LLAgent = require 'LLAgent'
+UI = require 'UI'
+
+local GROUPS = LLAgent.getGroups()
+
+-- Choose one of the groups randomly and send group message
+math.randomseed(os.time())
+group_info = GROUPS[math.random(#GROUPS)]
+LLChat.startGroupChat(group_info.id)
+response = UI.popup:alertYesCancel('Started group chat with ' .. group_info.name .. ' group. Send greetings?')
+if response == 'OK' then
+ LLChat.sendGroupIM('Greetings', group_info.id)
+end
diff --git a/indra/newview/scripts/lua/test_inv_resultset.lua b/indra/newview/scripts/lua/test_inv_resultset.lua
new file mode 100644
index 0000000000..c31cfe3c67
--- /dev/null
+++ b/indra/newview/scripts/lua/test_inv_resultset.lua
@@ -0,0 +1,18 @@
+local LLInventory = require 'LLInventory'
+local inspect = require 'inspect'
+
+print('basic folders:')
+print(inspect(LLInventory.getFolderTypeNames()))
+
+local folder = LLInventory.getBasicFolderID('my_otfts')
+print(`folder = {folder}`)
+local result = LLInventory.getDirectDescendants(folder)
+print(`type(result) = {type(result)}`)
+print(#result.categories, 'categories:')
+for i, cat in pairs(result.categories) do
+ print(`{i}: {cat.name}`)
+end
+print(#result.items, 'items')
+for i, item in pairs(result.items) do
+ print(`{i}: {item.name}`)
+end
diff --git a/indra/newview/scripts/lua/test_login.lua b/indra/newview/scripts/lua/test_login.lua
new file mode 100644
index 0000000000..54d3635a41
--- /dev/null
+++ b/indra/newview/scripts/lua/test_login.lua
@@ -0,0 +1,10 @@
+inspect = require 'inspect'
+login = require 'login'
+
+local grid = 'agni'
+print(inspect(login.savedLogins(grid)))
+
+print(inspect(login.login{
+ username='Your Username',
+ grid=grid
+ }))
diff --git a/indra/newview/scripts/lua/test_logout.lua b/indra/newview/scripts/lua/test_logout.lua
new file mode 100644
index 0000000000..b1ac59e38c
--- /dev/null
+++ b/indra/newview/scripts/lua/test_logout.lua
@@ -0,0 +1,3 @@
+logout = require 'logout'
+
+logout()
diff --git a/indra/newview/scripts/lua/test_luafloater_demo.lua b/indra/newview/scripts/lua/test_luafloater_demo.lua
new file mode 100644
index 0000000000..23310c6176
--- /dev/null
+++ b/indra/newview/scripts/lua/test_luafloater_demo.lua
@@ -0,0 +1,39 @@
+local leap = require 'leap'
+local startup = require 'startup'
+local UI = require 'UI'
+
+local flt = UI.Floater(
+ 'luafloater_demo.xml',
+ {show_time_lbl = {"right_mouse_down", "double_click"}})
+
+-- override base-class handleEvents() to report the event data in the floater's display field
+function flt:handleEvents(event_data)
+ self:post({action="add_text", ctrl_name="events_editor", value = event_data})
+ -- forward the call to base-class handleEvents()
+ return UI.Floater.handleEvents(self, event_data)
+end
+
+function flt:commit_disable_ctrl(event_data)
+ self:post({action="set_enabled", ctrl_name="open_btn", value = not event_data.value})
+end
+
+function flt:commit_title_cmb(event_data)
+ self:post({action="set_title", value=event_data.value})
+end
+
+function flt:commit_open_btn(event_data)
+ floater_name = self:request({action="get_value", ctrl_name='openfloater_cmd'}).value
+ leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"})
+end
+
+local function getCurrentTime()
+ local currentTime = os.date("*t")
+ return string.format("%02d:%02d:%02d", currentTime.hour, currentTime.min, currentTime.sec)
+end
+
+function flt:double_click_show_time_lbl(event_data)
+ self:post({action="set_value", ctrl_name="time_lbl", value=getCurrentTime()})
+end
+
+startup.wait('STATE_LOGIN_WAIT')
+flt:show()
diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua
new file mode 100644
index 0000000000..5f929c0d0c
--- /dev/null
+++ b/indra/newview/scripts/lua/test_luafloater_gesture_list.lua
@@ -0,0 +1,27 @@
+local LLGesture = require 'LLGesture'
+local startup = require 'startup'
+local UI = require 'UI'
+
+local flt = UI.Floater(
+ "luafloater_gesture_list.xml",
+ {gesture_list = {"double_click"}})
+
+function flt:post_build(event_data)
+ local gestures_uuid = LLGesture.getActiveGestures()
+ local action_data = {}
+ action_data.action = "add_list_element"
+ action_data.ctrl_name = "gesture_list"
+ local gestures = {}
+ for uuid, info in pairs(gestures_uuid) do
+ table.insert(gestures, {value = uuid, columns={column = "gesture_name", value = info.name}})
+ end
+ action_data.value = gestures
+ self:post(action_data)
+end
+
+function flt:double_click_gesture_list(event_data)
+ LLGesture.startGesture(event_data.value)
+end
+
+startup.wait('STATE_STARTED')
+flt:show()
diff --git a/indra/newview/scripts/lua/test_luafloater_speedometer.lua b/indra/newview/scripts/lua/test_luafloater_speedometer.lua
new file mode 100644
index 0000000000..2cdd41fd7e
--- /dev/null
+++ b/indra/newview/scripts/lua/test_luafloater_speedometer.lua
@@ -0,0 +1,31 @@
+local leap = require 'leap'
+local startup = require 'startup'
+local Timer = (require 'timers').Timer
+local UI = require 'UI'
+local popup = UI.popup
+local max_speed = 0
+local flt = UI.Floater("luafloater_speedometer.xml")
+startup.wait('STATE_STARTED')
+
+local timer
+
+function flt:floater_close(event_data)
+ if timer then
+ timer:cancel()
+ end
+ popup:tip(string.format("Registered max speed: %.2f m/s", max_speed))
+end
+
+local function idle(event_data)
+ local speed = leap.request('LLVOAvatar', {op='getSpeed'})['value']
+ flt:post({action="set_value", ctrl_name="speed_lbl", value = string.format("%.2f", speed)})
+ max_speed=math.max(max_speed, speed)
+end
+
+msg = 'Are you sure you want to run this "speedometer" script?'
+response = popup:alertYesCancel(msg)
+
+if response == 'OK' then
+ flt:show()
+ timer = Timer(1, idle, true) -- iterate
+end
diff --git a/indra/newview/scripts/lua/test_mapargs.lua b/indra/newview/scripts/lua/test_mapargs.lua
new file mode 100644
index 0000000000..999a57acb4
--- /dev/null
+++ b/indra/newview/scripts/lua/test_mapargs.lua
@@ -0,0 +1,68 @@
+local mapargs = require 'mapargs'
+local inspect = require 'inspect'
+
+function tabfunc(...)
+ local a = mapargs({'a1', 'a2', 'a3'}, ...)
+ print(inspect(a))
+end
+
+print('----------')
+print('f(10, 20, 30)')
+tabfunc(10, 20, 30)
+print('f(10, nil, 30)')
+tabfunc(10, nil, 30)
+print('f{10, 20, 30}')
+tabfunc{10, 20, 30}
+print('f{10, nil, 30}')
+tabfunc{10, nil, 30}
+print('f{a3=300, a1=100}')
+tabfunc{a3=300, a1=100}
+print('f{1, a3=3}')
+tabfunc{1, a3=3}
+print('f{a3=3, 1}')
+tabfunc{a3=3, 1}
+print('----------')
+
+if false then
+ -- the code below was used to explore ideas that became mapargs()
+ mixed = { '[1]', nil, '[3]', abc='[abc]', '[3]', def='[def]' }
+ local function showtable(desc, t)
+ print(string.format('%s (len %s)\n%s', desc, #t, inspect(t)))
+ end
+ showtable('mixed', mixed)
+
+ print('ipairs(mixed)')
+ for k, v in ipairs(mixed) do
+ print(string.format('[%s] = %s', k, tostring(v)))
+ end
+
+ print('table.pack(mixed)')
+ print(inspect(table.pack(mixed)))
+
+ local function nilarg(desc, a, b, c)
+ print(desc)
+ print('a = ' .. tostring(a))
+ print('b = ' .. tostring(b))
+ print('c = ' .. tostring(c))
+ end
+
+ nilarg('nilarg(1)', 1)
+ nilarg('nilarg(1, nil, 3)', 1, nil, 3)
+
+ local function nilargs(desc, ...)
+ args = table.pack(...)
+ showtable(desc, args)
+ end
+
+ nilargs('nilargs{a=1, b=2, c=3}', {a=1, b=2, c=3})
+ nilargs('nilargs(1, 2, 3)', 1, 2, 3)
+ nilargs('nilargs(1, nil, 3)', 1, nil, 3)
+ nilargs('nilargs{1, 2, 3}', {1, 2, 3})
+ nilargs('nilargs{1, nil, 3}', {1, nil, 3})
+
+ print('table.unpack({1, nil, 3})')
+ a, b, c = table.unpack({1, nil, 3})
+ print('a = ' .. tostring(a))
+ print('b = ' .. tostring(b))
+ print('c = ' .. tostring(c))
+end
diff --git a/indra/newview/scripts/lua/test_nearby_avatars.lua b/indra/newview/scripts/lua/test_nearby_avatars.lua
new file mode 100644
index 0000000000..c7fa686076
--- /dev/null
+++ b/indra/newview/scripts/lua/test_nearby_avatars.lua
@@ -0,0 +1,25 @@
+inspect = require 'inspect'
+LLAgent = require 'LLAgent'
+
+-- Get the list of nearby avatars and print the info
+local nearby_avatars = LLAgent.getNearbyAvatarsList()
+if nearby_avatars.result.length == 0 then
+ print("No avatars nearby")
+else
+ print("Nearby avatars:")
+ for _, av in pairs(nearby_avatars.result) do
+ print(av.name ..' ID: ' .. av.id ..' Global pos:' .. inspect(av.global_pos))
+ end
+end
+
+-- Get the list of nearby objects in 3m range and print the info
+local nearby_objects = LLAgent.getNearbyObjectsList(3)
+if nearby_objects.result.length == 0 then
+ print("No objects nearby")
+else
+ print("Nearby objects:")
+ local pos={}
+ for _, obj in pairs(nearby_objects.result) do
+ print('ID: ' .. obj.id ..' Global pos:' .. inspect(obj.global_pos))
+ end
+end
diff --git a/indra/newview/scripts/lua/test_popup.lua b/indra/newview/scripts/lua/test_popup.lua
new file mode 100644
index 0000000000..7a11895669
--- /dev/null
+++ b/indra/newview/scripts/lua/test_popup.lua
@@ -0,0 +1,10 @@
+UI = require 'UI'
+popup = UI.popup
+startup = require 'startup'
+
+startup.wait('STATE_STARTED')
+
+response = popup:alert('This just has a Close button')
+response = popup:alertOK(string.format('You said "%s", is that OK?', response))
+response = popup:alertYesCancel(string.format('You said "%s"', response))
+popup:tip(string.format('You said "%s"', response))
diff --git a/indra/newview/scripts/lua/test_result_view.lua b/indra/newview/scripts/lua/test_result_view.lua
new file mode 100644
index 0000000000..304633a472
--- /dev/null
+++ b/indra/newview/scripts/lua/test_result_view.lua
@@ -0,0 +1,55 @@
+-- Verify the functionality of result_view.
+result_view = require 'result_view'
+
+print('alphabet')
+alphabet = "abcdefghijklmnopqrstuvwxyz"
+assert(#alphabet == 26)
+alphabits = string.split(alphabet, '')
+
+print('function slice()')
+function slice(t, index, count)
+ return table.move(t, index, index + count - 1, 1, {})
+end
+
+print('verify slice()')
+-- verify that slice() does what we expect
+assert(table.concat(slice(alphabits, 4, 3)) == "def")
+assert(table.concat(slice(alphabits, 14, 3)) == "nop")
+assert(table.concat(slice(alphabits, 25, 3)) == "yz")
+
+print('function fetch()')
+function fetch(key, index)
+ -- fetch function is defined to be 0-relative: fix for Lua data
+ -- constrain view of alphabits to slices of at most 3 elements
+ return slice(alphabits, index+1, 3), index
+end
+
+print('result_view()')
+-- for test purposes, key is irrelevant, so just 'key'
+view = result_view({'key', #alphabits}, fetch)
+
+print('function check_iter()')
+function check_iter(...)
+ result = {}
+ for k, v in ... do
+ table.insert(result, v)
+ end
+ assert(table.concat(result) == alphabet)
+end
+
+print('check_iter(pairs(view))')
+check_iter(pairs(view))
+print('check_iter(ipairs(view))')
+check_iter(ipairs(view))
+print('check_iter(view)')
+check_iter(view)
+
+print('raw index access')
+assert(view[5] == 'e')
+assert(view[10] == 'j')
+assert(view[15] == 'o')
+assert(view[20] == 't')
+assert(view[25] == 'y')
+
+print('Success!')
+
diff --git a/indra/newview/scripts/lua/test_screen_position.lua b/indra/newview/scripts/lua/test_screen_position.lua
new file mode 100644
index 0000000000..94d57339b1
--- /dev/null
+++ b/indra/newview/scripts/lua/test_screen_position.lua
@@ -0,0 +1,8 @@
+LLAgent = require 'LLAgent'
+
+local screen_pos = LLAgent.getAgentScreenPos()
+if screen_pos.onscreen then
+ print("Avatar screen coordinates X: " .. screen_pos.x .. " Y: " .. screen_pos.y)
+else
+ print("Avatar is not on the screen")
+end
diff --git a/indra/newview/scripts/lua/test_setdtor.lua b/indra/newview/scripts/lua/test_setdtor.lua
new file mode 100644
index 0000000000..ec5cd47e93
--- /dev/null
+++ b/indra/newview/scripts/lua/test_setdtor.lua
@@ -0,0 +1,91 @@
+inspect = require 'inspect'
+
+print('initial setdtor')
+bye = LL.setdtor('initial setdtor', 'Goodbye world!', print)
+
+print('arithmetic')
+n = LL.setdtor('arithmetic', 11, print)
+print("n =", n)
+print("n._target =", n._target)
+print(pcall(function() n._target = 12 end))
+print("getmetatable(n) =", inspect(getmetatable(n)))
+print("-n =", -n)
+for i = 10, 12 do
+ -- Comparison metamethods are only called if both operands have the same
+ -- metamethod.
+ tempi = LL.setdtor('tempi', i, function(n) print('temp', i) end)
+ print(`n < {i}`, n < tempi)
+ print(`n <= {i}`, n <= tempi)
+ print(`n == {i}`, n == tempi)
+ print(`n ~= {i}`, n ~= tempi)
+ print(`n >= {i}`, n >= tempi)
+ print(`n > {i}`, n > tempi)
+end
+i = 2
+print(`n + {i} =`, n + i)
+print(`{i} + n =`, i + n)
+print(`n - {i} =`, n - i)
+print(`{i} - n =`, i - n)
+print(`n * {i} =`, n * i)
+print(`{i} * n =`, i * n)
+print(`n / {i} =`, n / i)
+print(`{i} / n =`, i / n)
+print(`n // {i} =`, n // i)
+print(`{i} // n =`, i // n)
+print(`n % {i} =`, n % i)
+print(`{i} % n =`, i % n)
+print(`n ^ {i} =`, n ^ i)
+print(`{i} ^ n =`, i ^ n)
+
+print('string')
+s = LL.setdtor('string', 'hello', print)
+print('s =', s)
+print('#s =', #s)
+print('s .. " world" =', s .. " world")
+print('"world " .. s =', "world " .. s)
+
+print('table')
+t = LL.setdtor('table', {'[1]', '[2]', abc='.abc', def='.def'},
+ function(t) print(inspect(t)) end)
+print('t =', inspect(t))
+print('t._target =', inspect(t._target))
+print('#t =', #t)
+print('next(t) =', next(t))
+print('next(t, 1) =', next(t, 1))
+print('t[2] =', t[2])
+print('t.def =', t.def)
+t[1] = 'new [1]'
+print('t[1] =', t[1])
+print('for k, v in pairs(t) do')
+for k, v in pairs(t) do
+ print(`{k}: {v}`)
+end
+print('for k, v in ipairs(t) do')
+for k, v in ipairs(t) do
+ print(`{k}: {v}`)
+end
+print('for k, v in t do')
+for k, v in t do
+ print(`{k}: {v}`)
+end
+-- and now for something completely different
+setmetatable(
+ t._target,
+ {
+ __iter = function(arg)
+ return next, {'alternate', '__iter'}
+ end
+ }
+)
+print('for k, v in t with __iter() metamethod do')
+for k, v in t do
+ print(`{k}: {v}`)
+end
+
+print('function')
+f = LL.setdtor('function', function(a, b) return (a .. b) end, print)
+print('f =', f)
+print('f._target =', f._target)
+print('f("Hello", " world") =', f("Hello", " world"))
+
+print('cleanup')
diff --git a/indra/newview/scripts/lua/test_snapshot.lua b/indra/newview/scripts/lua/test_snapshot.lua
new file mode 100644
index 0000000000..d7c878833b
--- /dev/null
+++ b/indra/newview/scripts/lua/test_snapshot.lua
@@ -0,0 +1,15 @@
+local UI = require 'UI'
+
+PATH = 'E:\\'
+-- 'png', 'jpeg' or 'bmp'
+EXT = '.png'
+
+NAME_SIMPLE = 'Snapshot_simple' .. '_' .. os.date("%Y-%m-%d_%H-%M-%S")
+UI.snapshot(PATH .. NAME_SIMPLE .. EXT)
+
+NAME_ARGS = 'Snapshot_args' .. '_' .. os.date("%Y-%m-%d_%H-%M-%S")
+
+-- 'COLOR' or 'DEPTH'
+TYPE = 'COLOR'
+UI.snapshot{PATH .. NAME_ARGS .. EXT, width = 700, height = 400,
+ type = TYPE, showui = false, showhud = false}
diff --git a/indra/newview/scripts/lua/test_timers.lua b/indra/newview/scripts/lua/test_timers.lua
new file mode 100644
index 0000000000..be5001aa16
--- /dev/null
+++ b/indra/newview/scripts/lua/test_timers.lua
@@ -0,0 +1,63 @@
+local timers = require 'timers'
+
+-- This t0 is constructed for 10 seconds, but its purpose is to exercise the
+-- query and cancel methods. It would print "t0 fired at..." if it fired, but
+-- it doesn't, so you don't see that message. Instead you see that isRunning()
+-- is true, that timeUntilCall() is (true, close to 10), that cancel() returns
+-- true. After that, isRunning() is false, timeUntilCall() returns (false, 0),
+-- and a second cancel() returns false.
+print('t0(10)')
+start = os.clock()
+t0 = timers.Timer(10, function() print('t0 fired at', os.clock() - start) end)
+print('t0:isRunning(): ', t0:isRunning())
+print('t0:timeUntilCall(): ', t0:timeUntilCall())
+print('t0:cancel(): ', t0:cancel())
+print('t0:isRunning(): ', t0:isRunning())
+print('t0:timeUntilCall(): ', t0:timeUntilCall())
+print('t0:cancel(): ', t0:cancel())
+
+-- t1 is supposed to fire after 5 seconds, but it doesn't wait, so you see the
+-- t2 messages immediately after.
+print('t1(5)')
+start = os.clock()
+t1 = timers.Timer(5, function() print('t1 fired at', os.clock() - start) end)
+
+-- t2 illustrates that instead of passing a callback to new(), you can
+-- override the timer instance's tick() method. But t2 doesn't wait either, so
+-- you see the Timer(5) message immediately.
+print('t2(2)')
+start = os.clock()
+t2 = timers.Timer(2)
+function t2:tick()
+ print('t2 fired at', os.clock() - start)
+end
+
+-- This anonymous timer blocks the calling fiber for 5 seconds. Other fibers
+-- are free to run during that time, so you see the t2 callback message and
+-- then the t1 callback message before the Timer(5) completion message.
+print('Timer(5) waiting')
+start = os.clock()
+timers.Timer(5, 'wait')
+print(string.format('Timer(5) waited %f seconds', os.clock() - start))
+
+-- This test demonstrates a repeating timer. It also shows that you can (but
+-- need not) use a coroutine as the timer's callback function: unlike Python,
+-- Lua doesn't disinguish between yield() and return. A coroutine wrapped with
+-- coroutine.wrap() looks to Lua just like any other function that you can
+-- call repeatedly and get a result each time. We use that to count the
+-- callback calls and stop after a certain number. Of course that could also
+-- be arranged in a plain function by incrementing a script-scope counter, but
+-- it's worth knowing that a coroutine timer callback can be used to manage
+-- more complex control flows.
+start = os.clock()
+timers.Timer(
+ 2,
+ coroutine.wrap(function()
+ for i = 1,5 do
+ print('repeat(2) timer fired at ', os.clock() - start)
+ coroutine.yield(nil) -- keep running
+ end
+ print('repeat(2) timer fired last at ', os.clock() - start)
+ return true -- stop
+ end),
+ true) -- iterate
diff --git a/indra/newview/scripts/lua/test_toolbars.lua b/indra/newview/scripts/lua/test_toolbars.lua
new file mode 100644
index 0000000000..9cd1043446
--- /dev/null
+++ b/indra/newview/scripts/lua/test_toolbars.lua
@@ -0,0 +1,26 @@
+UI = require 'UI'
+
+local BUTTONS = UI.getToolbarBtnNames()
+local TOOLBARS = {'left','right','bottom'}
+
+-- Clear the toolbars and then add the toolbar buttons to the random toolbar
+response = UI.popup:alertYesCancel('Toolbars will be randomly reshuffled. Proceed?')
+if response == 'OK' then
+ UI.clearAllToolbars()
+ math.randomseed(os.time())
+
+ -- add the buttons to the random toolbar
+ for i = 1, #BUTTONS do
+ UI.addToolbarBtn(BUTTONS[i], TOOLBARS[math.random(3)])
+ end
+
+ -- remove some of the added buttons from the toolbars
+ for i = 1, #BUTTONS do
+ if math.random(100) < 30 then
+ UI.removeToolbarBtn(BUTTONS[i])
+ end
+ end
+ UI.popup:tip('Toolbars were reshuffled')
+else
+ UI.popup:tip('Canceled')
+end
diff --git a/indra/newview/scripts/lua/test_top_menu.lua b/indra/newview/scripts/lua/test_top_menu.lua
new file mode 100644
index 0000000000..f877cda5eb
--- /dev/null
+++ b/indra/newview/scripts/lua/test_top_menu.lua
@@ -0,0 +1,52 @@
+UI = require 'UI'
+
+--Add new drop-down 'LUA Menu' to the Top menu.
+local MENU_NAME = "lua_menu"
+UI.addMenu{name=MENU_NAME,label="LUA Menu"}
+
+--Add two new menu items to the 'LUA Menu': 'Debug console' and 'Scripts'
+UI.addMenuItem{name="lua_debug",label="Debug console",
+ param="lua_debug",
+ func="Floater.ToggleOrBringToFront",
+ parent_menu=MENU_NAME}
+
+UI.addMenuItem{name="lua_scripts",label="Scripts",
+ param="lua_scripts",
+ func="Floater.ToggleOrBringToFront",
+ parent_menu=MENU_NAME}
+
+--Add menu separator to the 'LUA Menu' under added menu items
+UI.addMenuSeparator{parent_menu=MENU_NAME}
+
+--Add 'Demo scripts...' branch to the 'LUA Menu'
+local DEMO_BRANCH = "demo_scripts"
+UI.addMenuBranch{name=DEMO_BRANCH,label="Demo scripts...",parent_menu=MENU_NAME}
+
+--Add menu items to the 'Demo scripts...' branch, which will invoke specified script on click
+UI.addMenuItem{name="speedometer",label="Speedometer",
+ param="test_luafloater_speedometer.lua",
+ func="Lua.RunScript",
+ parent_menu=DEMO_BRANCH}
+
+UI.addMenuItem{name="gesture_list",label="Gesture list",
+ param="test_luafloater_gesture_list.lua",
+ func="Lua.RunScript",
+ parent_menu=DEMO_BRANCH}
+
+--Add one more menu separator
+UI.addMenuSeparator{parent_menu=MENU_NAME}
+
+--Add 'About...' branch to the 'LUA Menu'
+local ABOUT_BRANCH = "about_branch"
+UI.addMenuBranch{name=ABOUT_BRANCH,label="About...",parent_menu=MENU_NAME}
+
+--Add two new menu items to the 'About...' branch
+UI.addMenuItem{name="lua_info",label="Lua...",
+ param="https://www.lua.org/about.html",
+ func="Advanced.ShowURL",
+ parent_menu=ABOUT_BRANCH}
+
+UI.addMenuItem{name="lua_info",label="Luau...",
+ param="https://luau-lang.org/",
+ func="Advanced.ShowURL",
+ parent_menu=ABOUT_BRANCH}
diff --git a/indra/newview/scripts/lua/testmod.lua b/indra/newview/scripts/lua/testmod.lua
new file mode 100644
index 0000000000..60f7f80db1
--- /dev/null
+++ b/indra/newview/scripts/lua/testmod.lua
@@ -0,0 +1,2 @@
+print('loaded scripts/lua/testmod.lua')
+return function () return 'hello from scripts/lua/testmod.lua' end
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 1fd46fc637..db9b54f704 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -458,6 +458,9 @@
name="InventoryBackgroundColor"
reference="DkGray2" />
<color
+ name="InventoryFavoriteColor"
+ reference="Yellow" />
+ <color
name="InventoryFocusOutlineColor"
reference="White_25" />
<color
diff --git a/indra/newview/skins/default/textures/bottomtray/Dpad.png b/indra/newview/skins/default/textures/bottomtray/Dpad.png
new file mode 100644
index 0000000000..00fcb4beea
--- /dev/null
+++ b/indra/newview/skins/default/textures/bottomtray/Dpad.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Icon_Pointer.png b/indra/newview/skins/default/textures/icons/Icon_Pointer.png
new file mode 100644
index 0000000000..021942a8aa
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Icon_Pointer.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png
new file mode 100644
index 0000000000..b71b202234
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png
new file mode 100644
index 0000000000..7d55fb5cfe
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index f824816183..64e2b417fa 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -87,7 +87,7 @@ with the same filename but different name
<texture name="BreadCrumbBtn_Left_Off" file_name="widgets/BreadCrumbBtn_Left_Off.png" preload="false"/>
<texture name="BreadCrumbBtn_Left_Over" file_name="widgets/BreadCrumbBtn_Left_Over.png" preload="false"/>
<texture name="BreadCrumbBtn_Left_Press" file_name="widgets/BreadCrumbBtn_Left_Press.png" preload="false"/>
-
+
<texture name="BreadCrumbBtn_Middle_Disabled" file_name="widgets/BreadCrumbBtn_Middle_Disabled.png" preload="false"/>
<texture name="BreadCrumbBtn_Middle_Off" file_name="widgets/BreadCrumbBtn_Middle_Off.png" preload="false"/>
<texture name="BreadCrumbBtn_Middle_Over" file_name="widgets/BreadCrumbBtn_Middle_Over.png" preload="false"/>
@@ -194,7 +194,7 @@ with the same filename but different name
<texture name="Copy" file_name="icons/Copy.png" preload="false" />
<texture name="CopyBright" file_name="icons/CopyBright.png" preload="false" />
-
+
<texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />
<texture name="ChatBarHandle" file_name="bottomtray/ChatBarHandle.png" preload="false" />
@@ -246,7 +246,7 @@ with the same filename but different name
<texture name="Group_Notices" file_name="icons/Group_Notices.png" preload="false" />
<texture name="Hand" file_name="icons/hand.png" preload="false" />
-
+
<texture name="Help_Press" file_name="navbar/Help_Press.png" preload="false" />
<texture name="Hierarchy_View_Disabled" file_name="icons/Hierarchy_View_Disabled.png" preload="false" />
@@ -259,16 +259,16 @@ with the same filename but different name
<texture name="Icon_Close_Foreground" file_name="windows/Icon_Close_Foreground.png" preload="true" />
<texture name="Icon_Close_Press" file_name="windows/Icon_Close_Press.png" preload="true" />
<texture name="Icon_Close_Toast" file_name="windows/Icon_Close_Toast.png" preload="true" />
-
+
<texture name="Icon_Copy" file_name="icons/copy_clipboard.png" preload="true" />
-
+
<texture name="Icon_Delete" file_name="icons/delete_icon.png" preload="true" />
<texture name="Icon_Dock_Foreground" file_name="windows/Icon_Dock_Foreground.png" preload="true" />
<texture name="Icon_Dock_Press" file_name="windows/Icon_Dock_Press.png" preload="true" />
<texture name="Icon_File_Upload" file_name="icons/file_upload.png" preload="true" />
-
+
<texture name="Icon_For_Sale" file_name="icons/Icon_For_Sale.png" preload="false" />
<texture name="Icon_Gear_Background" file_name="windows/Icon_Gear_Background.png" preload="false" />
@@ -281,14 +281,14 @@ with the same filename but different name
<texture name="Icon_Minimize_Foreground" file_name="windows/Icon_Minimize_Foreground.png" preload="true" />
<texture name="Icon_Minimize_Press" file_name="windows/Icon_Minimize_Press.png" preload="true" />
-
+
<texture name="Icon_Paste" file_name="icons/paste_clipboard.png" preload="true" />
<texture name="Icon_Restore_Foreground" file_name="windows/Icon_Restore_Foreground.png" preload="false" />
<texture name="Icon_Restore_Press" file_name="windows/Icon_Restore_Press.png" preload="false" />
<texture name="Icon_Snapshot" file_name="icons/snapshot_icon.png" preload="true" />
-
+
<texture name="Icon_Use_Texture" file_name="icons/texture_icon.png" preload="true" />
<texture name="Info" file_name="icons/Info.png" preload="false" />
@@ -308,6 +308,8 @@ with the same filename but different name
<texture name="Inv_CallingCard" file_name="icons/Inv_CallingCard.png" preload="false" />
<texture name="Inv_Clothing" file_name="icons/Inv_Clothing.png" preload="false" />
<texture name="Inv_Eye" file_name="icons/Inv_Eye.png" preload="false" />
+ <texture name="Inv_Favorite_Star_Content" file_name="icons/Inv_Favorite_Star_Content.png" preload="false" />
+ <texture name="Inv_Favorite_Star_Full" file_name="icons/Inv_Favorite_Star_Full.png" preload="false" />
<texture name="Inv_FolderClosed" file_name="icons/Inv_FolderClosed.png" preload="false" />
<texture name="Inv_FolderOpen" file_name="icons/Inv_FolderOpen.png" preload="false" />
<texture name="Inv_Gesture" file_name="icons/Inv_Gesture.png" preload="false" />
@@ -322,7 +324,7 @@ with the same filename but different name
<texture name="Inv_LostOpen" file_name="icons/Inv_LostOpen.png" preload="false" />
<texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" />
<texture name="Inv_Material" file_name="icons/Inv_Material.png" preload="false" />
- <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" />
+ <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" />
<texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" />
<texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" />
<texture name="Inv_Object_Multi" file_name="icons/Inv_Object_Multi.png" preload="false" />
@@ -377,7 +379,7 @@ with the same filename but different name
<texture name="Locked_Icon" file_name="icons/Locked_Icon.png" preload="false" />
<texture name="Map_Placeholder_Icon" file_name="icons/map_placeholder.png" preload="true" />
-
+
<texture name="Marketplace_Dropzone_Background" file_name="widgets/Marketplace_Dropzone_Background.png" preload="true" />
<texture name="MarketplaceBtn_Off" file_name="widgets/MarketplaceBtn_Off.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" />
<texture name="MarketplaceBtn_Selected" file_name="widgets/MarketplaceBtn_Selected.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" />
@@ -393,7 +395,7 @@ with the same filename but different name
<texture name="ModelImport_Status_Good" file_name="green_checkmark.png" preload="false"/>
<texture name="ModelImport_Status_Warning" file_name="lag_status_warning.tga" preload="false"/>
<texture name="ModelImport_Status_Error" file_name="red_x.png" preload="false"/>
-
+
<texture name="MouseLook_View_Off" file_name="bottomtray/Mouselook_View_Off.png" preload="false" />
<texture name="MouseLook_View_On" file_name="bottomtray/Mouselook_View_On.png" preload="false" />
@@ -549,7 +551,7 @@ with the same filename but different name
<texture name="Profile_Perm_Objects_Enabled" file_name="icons/Profile_Perm_Objects_Enabled.png" preload="true"/>
<texture name="Profile_Perm_Online_Disabled" file_name="icons/Profile_Perm_Online_Disabled.png" preload="true"/>
<texture name="Profile_Perm_Online_Enabled" file_name="icons/Profile_Perm_Online_Enabled.png" preload="true"/>
-
+
<texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
<texture name="ProgressBarSolid" file_name="widgets/ProgressBarSolid.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
<texture name="ProgressTrack" file_name="widgets/ProgressTrack.png" preload="true" scale.left="4" scale.top="13" scale.right="148" scale.bottom="2" />
@@ -742,7 +744,7 @@ with the same filename but different name
<texture name="UpArrow_Off" file_name="icons/UpArrow_Off.png" preload="false" />
<texture name="Video_URL_Off" file_name="icons/Video_URL_Off.png" preload="true" />
-
+
<texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png" scale.left="2" scale.right="7" scale.bottom="8" scale.top="120" scale_type="scale_outer"/>
<texture name="VirtualTrackball_Moon_Back" file_name="widgets/track_control_moon_back.png" />
@@ -758,7 +760,7 @@ with the same filename but different name
<texture name="VirtualTrackball_Sphere" file_name="widgets/track_control_sphere.png" />
<texture name="VirtualTrackball_Sun_Back" file_name="widgets/track_control_sun_back.png" />
<texture name="VirtualTrackball_Sun_Front" file_name="widgets/track_control_sun_front.png" />
-
+
<texture name="Volume_Background" file_name="windows/Volume_Background.png" preload="false"
scale.left="6" scale.top="33" scale.right="63" scale.bottom="10" />
@@ -767,7 +769,7 @@ with the same filename but different name
<texture name="VoicePTT_Lvl3" file_name="bottomtray/VoicePTT_Lvl3.png" preload="false" />
<texture name="VoicePTT_Off" file_name="bottomtray/VoicePTT_Off.png" preload="false" />
<texture name="VoicePTT_On" file_name="bottomtray/VoicePTT_On.png" preload="false" />
-
+
<texture name="Wearables_Divider" file_name="windows/Wearables_Divider.png" preload="false" />
<texture name="Add_Icon" file_name="icons/add_icon.png" preload="false" />
@@ -882,7 +884,7 @@ with the same filename but different name
<texture name="buy_off" file_name="widgets/buy_off.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>
<texture name="buy_over" file_name="widgets/buy_over.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>
<texture name="buy_press" file_name="widgets/buy_press.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>
-
+
<texture name="hint_background" file_name="windows/hint_background.png" preload="false" scale.left="8" scale.top="70" scale.right="195" scale.bottom="11"/>
<texture name="hint_arrow_left" file_name="windows/hint_arrow_left.png" preload="false"/>
<texture name="hint_arrow_right" file_name="windows/hint_arrow_right.png" preload="false"/>
@@ -931,4 +933,5 @@ with the same filename but different name
<texture name="ProgressLarge_11" file_name="icons/ProgressLarge_11.png" preload="true" />
<texture name="ProgressLarge_12" file_name="icons/ProgressLarge_12.png" preload="true" />
+ <texture name="Icon_Pointer" file_name="icons/Icon_Pointer.png" preload="false"/>
</textures>
diff --git a/indra/newview/skins/default/xui/da/sidepanel_item_info.xml b/indra/newview/skins/default/xui/da/sidepanel_item_info.xml
index d52845160b..6a2acfedf7 100644
--- a/indra/newview/skins/default/xui/da/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/da/sidepanel_item_info.xml
@@ -15,6 +15,9 @@
<panel.string name="acquiredDate">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</panel.string>
+ <panel.string name="acquiredDateAMPM">
+ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local]
+ </panel.string>
<panel.string name="origin_inventory">
(Beholdning)
</panel.string>
diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml
index a7dff91311..038a2e0fcd 100644
--- a/indra/newview/skins/default/xui/da/strings.xml
+++ b/indra/newview/skins/default/xui/da/strings.xml
@@ -3723,6 +3723,10 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE].
<string name="conference-title-incoming">
Konference med [AGENT_NAME]
</string>
+ <string name="bot_warning">
+Du chatter med en bot, [NAME]. Del ikke personlige oplysninger.
+Læs mere på https://second.life/scripted-agents.
+ </string>
<string name="no_session_message">
(IM session eksisterer ikke)
</string>
diff --git a/indra/newview/skins/default/xui/de/floater_about_land.xml b/indra/newview/skins/default/xui/de/floater_about_land.xml
index bb9ab26ef5..9c93ff38ad 100644
--- a/indra/newview/skins/default/xui/de/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/de/floater_about_land.xml
@@ -25,7 +25,8 @@
<panel.string name="none_text">(keiner)</panel.string>
<panel.string name="sale_pending_text">(Wird verkauft)</panel.string>
<panel.string name="no_selection_text">Keine Parzelle ausgewählt.</panel.string>
- <panel.string name="time_stamp_template">[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]</panel.string>
+ <panel.string name="time_stamp_template_ampm">[wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,slt]</panel.string>
+ <panel.string name="time_stamp_template">[wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]</panel.string>
<text name="Name:">Name:</text>
<text name="Description:">Beschreibung:</text>
<text name="LandType">Typ:</text>
diff --git a/indra/newview/skins/default/xui/de/floater_inspect.xml b/indra/newview/skins/default/xui/de/floater_inspect.xml
index da97ceb2d8..a193e1123e 100644
--- a/indra/newview/skins/default/xui/de/floater_inspect.xml
+++ b/indra/newview/skins/default/xui/de/floater_inspect.xml
@@ -1,7 +1,10 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater min_width="460" name="inspect" title="OBJEKTE UNTERSUCHEN" width="460">
+ <floater.string name="timeStampAMPM">
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,slt]
+ </floater.string>
<floater.string name="timeStamp">
- [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
</floater.string>
<scroll_list name="object_list" tool_tip="Wählen Sie ein Objekt aus dieser Liste, um es in der Second Life-Welt zu markieren">
<scroll_list.columns label="Objektname" name="object_name"/>
diff --git a/indra/newview/skins/default/xui/de/panel_classified_info.xml b/indra/newview/skins/default/xui/de/panel_classified_info.xml
index 007e9d69f0..1b8caf5f78 100644
--- a/indra/newview/skins/default/xui/de/panel_classified_info.xml
+++ b/indra/newview/skins/default/xui/de/panel_classified_info.xml
@@ -13,7 +13,7 @@
[TELEPORT] teleportieren, [MAP] Karte, [PROFILE] Profil
</panel.string>
<panel.string name="date_fmt">
- [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+ [day,datetime,slt].[mthnum,datetime,slt].[year,datetime,slt]
</panel.string>
<panel.string name="auto_renew_on">
Aktiviert
diff --git a/indra/newview/skins/default/xui/de/panel_landmark_info.xml b/indra/newview/skins/default/xui/de/panel_landmark_info.xml
index 10cf34c170..8726d5e645 100644
--- a/indra/newview/skins/default/xui/de/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/de/panel_landmark_info.xml
@@ -15,8 +15,11 @@
<string name="server_forbidden_text">
Die Informationen über diesen Standort sind zugriffsbeschränkt. Bitte wenden Sie sich bezüglich Ihrer Berechtigungen an den Eigentümer der Parzelle.
</string>
+ <string name="acquired_date_ampm">
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local]
+ </string>
<string name="acquired_date">
- [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
</string>
<button name="back_btn" tool_tip="Hinten"/>
<text name="title" value="Ortsprofil"/>
diff --git a/indra/newview/skins/default/xui/de/panel_place_profile.xml b/indra/newview/skins/default/xui/de/panel_place_profile.xml
index 4077fdab36..a0b5a1e9dc 100644
--- a/indra/newview/skins/default/xui/de/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/de/panel_place_profile.xml
@@ -38,8 +38,11 @@
<string name="server_forbidden_text">
Die Informationen über diesen Standort sind zugriffsbeschränkt. Bitte wenden Sie sich bezüglich Ihrer Berechtigungen an den Eigentümer der Parzelle.
</string>
+ <string name="acquired_date_ampm">
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local]
+ </string>
<string name="acquired_date">
- [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
</string>
<button name="back_btn" tool_tip="Hinten"/>
<text name="title" value="Ortsprofil"/>
diff --git a/indra/newview/skins/default/xui/de/panel_profile_classified.xml b/indra/newview/skins/default/xui/de/panel_profile_classified.xml
index 5c11a01977..5a4b42870c 100644
--- a/indra/newview/skins/default/xui/de/panel_profile_classified.xml
+++ b/indra/newview/skins/default/xui/de/panel_profile_classified.xml
@@ -13,7 +13,7 @@
[TELEPORT] Teleportieren, [MAP] Karten, [PROFILE] Profil
</panel.string>
<panel.string name="date_fmt">
- [mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]
+ [day,datetime,slt].[mthnum,datetime,slt].[year,datetime,slt]
</panel.string>
<panel.string name="auto_renew_on">
Aktiviert
diff --git a/indra/newview/skins/default/xui/de/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/de/panel_profile_secondlife.xml
index baaa58e1d7..437cde99fe 100644
--- a/indra/newview/skins/default/xui/de/panel_profile_secondlife.xml
+++ b/indra/newview/skins/default/xui/de/panel_profile_secondlife.xml
@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Profil" name="panel_profile">
+ <string
+ name="date_format_full"
+ value="SL-Geburtstag: [day,datetime,utc]. [mth,datetime,utc]. [year,datetime,utc]" />
+ <string
+ name="date_format_short"
+ value="SL-Geburtstag: [day,datetime,utc]. [mth,datetime,utc]." />
<string name="status_online">
Zurzeit online
</string>
diff --git a/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml
index 602424821f..09447cbbaf 100644
--- a/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/de/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
<combo_box.item label="Klein (128x128)" name="Small(128x128)"/>
<combo_box.item label="Mittel (256x256)" name="Medium(256x256)"/>
<combo_box.item label="Groß (512x512)" name="Large(512x512)"/>
- <combo_box.item label="Aktuelles Fenster (512x512)" name="CurrentWindow"/>
+ <combo_box.item label="Aktuelles Fenster" name="CurrentWindow"/>
<combo_box.item label="Benutzerdefiniert" name="Custom"/>
</combo_box>
<spinner label="Breite x Höhe" name="inventory_snapshot_width"/>
diff --git a/indra/newview/skins/default/xui/de/panel_snapshot_options.xml b/indra/newview/skins/default/xui/de/panel_snapshot_options.xml
index dab20d63eb..2a51f10894 100644
--- a/indra/newview/skins/default/xui/de/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/de/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="Auf Datenträger speichern" name="save_to_computer_btn"/>
- <button label="In Inventar speichern ([AMOUNT] L$)" name="save_to_inventory_btn"/>
+ <button label="In Inventar speichern" name="save_to_inventory_btn"/>
<button label="Im Profil-Feed teilen" name="save_to_profile_btn"/>
<button label="Auf Facebook teilen" name="send_to_facebook_btn"/>
<button label="Auf Twitter teilen" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/de/panel_status_bar.xml b/indra/newview/skins/default/xui/de/panel_status_bar.xml
index 0829814220..e017c6dd82 100644
--- a/indra/newview/skins/default/xui/de/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/de/panel_status_bar.xml
@@ -10,7 +10,7 @@
[hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]
</panel.string>
<panel.string name="timeTooltip">
- [weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]
+ [weekday, datetime, slt], [day, datetime, slt]. [month, datetime, slt] [year, datetime, slt]
</panel.string>
<panel.string name="buycurrencylabel">
[AMT] L$
diff --git a/indra/newview/skins/default/xui/de/sidepanel_item_info.xml b/indra/newview/skins/default/xui/de/sidepanel_item_info.xml
index 168bb14248..30886d1433 100644
--- a/indra/newview/skins/default/xui/de/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/de/sidepanel_item_info.xml
@@ -19,7 +19,10 @@
Eigentümer kann:
</panel.string>
<panel.string name="acquiredDate">
- [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local]
+ </panel.string>
+ <panel.string name="acquiredDateAMPM">
+ [wkday,datetime,local]. [day,datetime,local]. [mth,datetime,local]. [year,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local]
</panel.string>
<panel.string name="origin_inventory">
(Inventar)
diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml
index b147c49224..2031f4cd2f 100644
--- a/indra/newview/skins/default/xui/de/strings.xml
+++ b/indra/newview/skins/default/xui/de/strings.xml
@@ -31,7 +31,6 @@ Sichtweite: [DRAW_DISTANCE] m
Bandbreite: [NET_BANDWITH] kbit/s
LOD-Faktor: [LOD_FACTOR]
Darstellungsqualität: [RENDER_QUALITY]
-Erweitertes Beleuchtungsmodell: [GPU_SHADERS]
Texturspeicher: [TEXTURE_MEMORY] MB</string>
<string name="AboutOSXHiDPI">HiDPI-Anzeigemodus: [HIDPI]</string>
<string name="AboutLibs">J2C-Decoderversion: [J2C_VERSION]
@@ -40,7 +39,7 @@ Audiotreiberversion: [AUDIO_DRIVER_VERSION]
LibVLC-Version: [LIBVLC_VERSION]
Voice-Server-Version: [VOICE_VERSION]</string>
<string name="AboutTraffic">Paketverlust: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1] %)</string>
- <string name="AboutTime">[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second,datetime,slt]</string>
+ <string name="AboutTime">[day, datetime, slt]. [month, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second,datetime,slt]</string>
<string name="ErrorFetchingServerReleaseNotesURL">Fehler beim Abrufen der URL für die Server-Versionshinweise.</string>
<string name="BuildConfiguration">Build-Konfiguration</string>
<string name="ProgressRestoring">Wird wiederhergestellt...</string>
@@ -813,7 +812,7 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich unter http://suppo
<string name="Unknown">(unbekannt)</string>
<string name="SummaryForTheWeek" value="Zusammenfassung für diese Woche, beginnend am "/>
<string name="NextStipendDay" value=". Der nächste Stipendium-Tag ist "/>
- <string name="GroupPlanningDate">[mthnum,datetime,utc]/[day,datetime,utc]/[year,datetime,utc]</string>
+ <string name="GroupPlanningDate">[day,datetime,utc].[mthnum,datetime,utc].[year,datetime,utc]</string>
<string name="GroupIndividualShare" value=" Gruppenanteil Einzelanteil"/>
<string name="GroupColumn" value="Gruppe"/>
<string name="Balance">Kontostand</string>
@@ -962,7 +961,7 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich unter http://suppo
<string name="GroupMoneyBalance">Kontostand</string>
<string name="GroupMoneyCredits">Danksagung</string>
<string name="GroupMoneyDebits">Soll</string>
- <string name="GroupMoneyDate">[weekday,datetime,utc] [mth,datetime,utc] [day,datetime,utc], [year,datetime,utc]</string>
+ <string name="GroupMoneyDate">[weekday,datetime,utc] [day,datetime,utc]. [mth,datetime,utc]. [year,datetime,utc]</string>
<string name="AcquiredItems">Erworbene Artikel</string>
<string name="Cancel">Abbrechen</string>
<string name="UploadingCosts">Das Hochladen von [NAME] kostet [AMOUNT] L$</string>
@@ -1614,6 +1613,10 @@ Falls diese Meldung weiterhin angezeigt wird, wenden Sie sich bitte an [SUPPORT_
<string name="conference-title-incoming">Konferenz mit [AGENT_NAME]</string>
<string name="inventory_item_offered-im">Inventarobjekt „[ITEM_NAME]“ angeboten</string>
<string name="inventory_folder_offered-im">Inventarordner „[ITEM_NAME]“ angeboten</string>
+ <string name="bot_warning">
+ Sie chatten mit einem Bot, [NAME]. Geben Sie keine persönlichen Informationen weiter.
+Erfahren Sie mehr unter https://second.life/scripted-agents.
+ </string>
<string name="share_alert">Objekte aus dem Inventar hier her ziehen</string>
<string name="facebook_post_success">Sie haben auf Facebook gepostet.</string>
<string name="flickr_post_success">Sie haben auf Flickr gepostet.</string>
@@ -1766,7 +1769,7 @@ Missbrauchsbericht</string>
<string name="dance6">Tanzen6</string>
<string name="dance7">Tanzen7</string>
<string name="dance8">Tanzen8</string>
- <string name="AvatarBirthDateFormat">[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]</string>
+ <string name="AvatarBirthDateFormat">[day,datetime,slt].[mthnum,datetime,slt].[year,datetime,slt]</string>
<string name="DefaultMimeType">Keine/Keiner</string>
<string name="texture_load_dimensions_error">Bilder, die größer sind als [WIDTH]*[HEIGHT] können nicht geladen werden</string>
<string name="outfit_photo_load_dimensions_error">Max. Fotogröße für Outfit ist [WIDTH]*[HEIGHT]. Bitte verkleinern Sie das Bild oder verwenden Sie ein anderes.</string>
diff --git a/indra/newview/skins/default/xui/en/control_table_contents_game_control.xml b/indra/newview/skins/default/xui/en/control_table_contents_game_control.xml
new file mode 100644
index 0000000000..a3a2d66e5e
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/control_table_contents_game_control.xml
@@ -0,0 +1,326 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+ <rows
+ enabled="false"
+ name="game_control_buttons"
+ value="">
+ <columns
+ type="icontext"
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ label="Game Control Buttons"
+ name="lst_action"
+ value="Dpad" />
+ </rows>
+ <rows
+ name="game_control_button_0"
+ value="game_control_button_0">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_0" />
+ </rows>
+ <rows
+ name="game_control_button_1"
+ value="game_control_button_1">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_1" />
+ </rows>
+ <rows
+ name="game_control_button_2"
+ value="game_control_button_2">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_2" />
+ </rows>
+ <rows
+ name="game_control_button_3"
+ value="game_control_button_3">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_3" />
+ </rows>
+ <rows
+ name="game_control_button_4"
+ value="game_control_button_4">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_4" />
+ </rows>
+ <rows
+ name="game_control_button_5"
+ value="game_control_button_5">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_5" />
+ </rows>
+ <rows
+ name="game_control_button_6"
+ value="game_control_button_6">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_6" />
+ </rows>
+ <rows
+ name="game_control_button_7"
+ value="game_control_button_7">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_7" />
+ </rows>
+ <rows
+ name="game_control_button_8"
+ value="game_control_button_8">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_8" />
+ </rows>
+ <rows
+ name="game_control_button_9"
+ value="game_control_button_9">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_9" />
+ </rows>
+ <rows
+ name="game_control_button_10"
+ value="game_control_button_10">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_10" />
+ </rows>
+ <rows
+ name="game_control_button_11"
+ value="game_control_button_11">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_11" />
+ </rows>
+ <rows
+ name="game_control_button_12"
+ value="game_control_button_12">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_12" />
+ </rows>
+ <rows
+ name="game_control_button_13"
+ value="game_control_button_13">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_13" />
+ </rows>
+ <rows
+ name="game_control_button_14"
+ value="game_control_button_14">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_14" />
+ </rows>
+ <rows
+ name="game_control_button_15"
+ value="game_control_button_15">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_15" />
+ </rows>
+ <rows
+ name="game_control_button_16"
+ value="game_control_button_16">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_16" />
+ </rows>
+ <rows
+ name="game_control_button_17"
+ value="game_control_button_17">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_17" />
+ </rows>
+ <rows
+ name="game_control_button_18"
+ value="game_control_button_18">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_18" />
+ </rows>
+ <rows
+ name="game_control_button_19"
+ value="game_control_button_19">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_19" />
+ </rows>
+ <rows
+ name="game_control_button_21"
+ value="game_control_button_21">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_21" />
+ </rows>
+ <rows
+ name="game_control_button_22"
+ value="game_control_button_22">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_22" />
+ </rows>
+ <rows
+ name="game_control_button_23"
+ value="game_control_button_23">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_23" />
+ </rows>
+ <rows
+ name="game_control_button_24"
+ value="game_control_button_24">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_24" />
+ </rows>
+ <rows
+ name="game_control_button_25"
+ value="game_control_button_25">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_25" />
+ </rows>
+ <rows
+ name="game_control_button_26"
+ value="game_control_button_26">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_26" />
+ </rows>
+ <rows
+ name="game_control_button_27"
+ value="game_control_button_27">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_27" />
+ </rows>
+ <rows
+ name="game_control_button_28"
+ value="game_control_button_28">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_28" />
+ </rows>
+ <rows
+ name="game_control_button_29"
+ value="game_control_button_29">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_29" />
+ </rows>
+ <rows
+ name="game_control_button_30"
+ value="game_control_button_30">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_30" />
+ </rows>
+ <rows
+ name="game_control_button_31"
+ value="game_control_button_31">
+ <columns
+ column="lst_action"
+ font="SansSerif"
+ halign="left"
+ name="lst_action"
+ value="BUTTON_31" />
+ </rows>
+</contents>
diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml
index 508aba6ae1..c5b42b6dae 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -125,6 +125,9 @@
name="no_selection_text">
No parcel selected.
</panel.string>
+ <panel.string name="time_stamp_template_ampm">
+ [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt]
+ </panel.string>
<panel.string name="time_stamp_template">
[wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt]
</panel.string>
diff --git a/indra/newview/skins/default/xui/en/floater_fast_timers.xml b/indra/newview/skins/default/xui/en/floater_fast_timers.xml
index 00411ba20b..ae907bcb5f 100644
--- a/indra/newview/skins/default/xui/en/floater_fast_timers.xml
+++ b/indra/newview/skins/default/xui/en/floater_fast_timers.xml
@@ -75,7 +75,7 @@
step_size="16"
doc_pos="0"
doc_size="3000"
- page_size="0"
+ page_size="50"
/>
</layout_panel>
<layout_panel name="timers_panel"
diff --git a/indra/newview/skins/default/xui/en/floater_inspect.xml b/indra/newview/skins/default/xui/en/floater_inspect.xml
index 9403d58441..a083683c23 100644
--- a/indra/newview/skins/default/xui/en/floater_inspect.xml
+++ b/indra/newview/skins/default/xui/en/floater_inspect.xml
@@ -12,6 +12,10 @@
title="INSPECT OBJECTS"
width="400">
<floater.string
+ name="timeStampAMPM">
+ [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt]
+ </floater.string>
+ <floater.string
name="timeStamp">
[wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt]
</floater.string>
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml
deleted file mode 100644
index 6c3214a76d..0000000000
--- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml
+++ /dev/null
@@ -1,421 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater
- legacy_header_height="18"
- height="340"
- layout="topleft"
- name="item properties"
- help_topic="item_properties"
- save_rect="true"
- title="INVENTORY ITEM PROPERTIES"
- width="350">
- <floater.string
- name="unknown">
- (unknown)
- </floater.string>
- <floater.string
- name="public">
- (public)
- </floater.string>
- <floater.string
- name="you_can">
- You can:
- </floater.string>
- <floater.string
- name="owner_can">
- Owner can:
- </floater.string>
- <floater.string
- name="acquiredDate">
- [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
- </floater.string>
- <icon
- follows="top|right"
- height="18"
- image_name="Lock"
- layout="topleft"
- left="276"
- mouse_opaque="true"
- name="IconLocked"
- top="4"
- width="18" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left="10"
- name="LabelItemNameTitle"
- top="25"
- width="78">
- Name:
- </text>
- <line_editor
- border_style="line"
- border_thickness="1"
- follows="left|top|right"
- height="16"
- layout="topleft"
- left_delta="78"
- max_length_bytes="63"
- name="LabelItemName"
- top_delta="0"
- width="252" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left="10"
- name="LabelItemDescTitle"
- top="45"
- width="78">
- Description:
- </text>
- <line_editor
- border_style="line"
- border_thickness="1"
- follows="left|top|right"
- height="16"
- layout="topleft"
- left_delta="78"
- max_length_bytes="127"
- name="LabelItemDesc"
- top_delta="0"
- width="252" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left="10"
- name="LabelCreatorTitle"
- top="65"
- width="78">
- Creator:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left_delta="78"
- name="LabelCreatorName"
- top_delta="0"
- translate="false"
- use_ellipses="true"
- width="170">
- TestString PleaseIgnore
- </text>
- <button
- follows="top|right"
- height="16"
- label="Profile..."
- layout="topleft"
- left_delta="174"
- name="BtnCreator"
- top_delta="0"
- width="78" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left="10"
- name="LabelOwnerTitle"
- top="85"
- width="78">
- Owner:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left_delta="78"
- name="LabelOwnerName"
- top_delta="0"
- translate="false"
- use_ellipses="true"
- width="170">
- TestString PleaseIgnore
- </text>
- <button
- follows="top|right"
- height="16"
- label="Profile..."
- layout="topleft"
- left_delta="174"
- name="BtnOwner"
- top_delta="0"
- width="78" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left="10"
- name="LabelAcquiredTitle"
- top="105"
- width="78">
- Acquired:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="16"
- layout="topleft"
- left_delta="78"
- name="LabelAcquiredDate"
- top_delta="0"
- width="252">
- Wed May 24 12:50:46 2006
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left="10"
- name="OwnerLabel"
- top="125"
- width="78">
- You:
- </text>
- <check_box
- height="16"
- label="Edit"
- layout="topleft"
- left_pad="5"
- name="CheckOwnerModify"
- top_delta="0"
- width="78" />
- <check_box
- height="16"
- label="Copy"
- layout="topleft"
- left_delta="0"
- name="CheckOwnerCopy"
- top_pad="5"
- width="88" />
- <check_box
- height="16"
- label="Resell"
- layout="topleft"
- left_delta="0"
- name="CheckOwnerTransfer"
- top_pad="5"
- width="106" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left="10"
- name="AnyoneLabel"
- top_pad="5"
- width="78">
- Anyone:
- </text>
- <check_box
- height="16"
- label="Copy"
- layout="topleft"
- left_pad="5"
- name="CheckEveryoneCopy"
- top_delta="0"
- width="130" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left="10"
- name="GroupLabel"
- top_pad="5"
- width="78">
- Group:
- </text>
- <check_box
- height="16"
- label="Share"
- layout="topleft"
- left_pad="5"
- name="CheckShareWithGroup"
- top_delta="5"
- width="106" />
- <text
- type="string"
- length="1"
- follows="left|top"
- height="25"
- layout="topleft"
- left="10"
- name="NextOwnerLabel"
- top_pad="5"
- width="78"
- word_wrap="true">
- Next owner:
- </text>
- <check_box
- height="16"
- label="Edit"
- layout="topleft"
- left_pad="5"
- name="CheckNextOwnerModify"
- top_delta="0"
- width="78" />
- <check_box
- height="16"
- label="Copy"
- layout="topleft"
- left_delta="0"
- name="CheckNextOwnerCopy"
- top_pad="5"
- width="88" />
- <check_box
- height="16"
- label="Resell"
- layout="topleft"
- left_delta="0"
- name="CheckNextOwnerTransfer"
- top_pad="5"
- width="106" />
- <check_box
- height="16"
- label="For Sale"
- layout="topleft"
- left="10"
- name="CheckPurchase"
- top_pad="5"
- width="78" />
- <combo_box
- height="19"
- left_pad="5"
- layout="topleft"
- follows="left|top"
- name="ComboBoxSaleType"
- width="110">
- <combo_box.item
- name="Copy"
- label="Copy"
- value="2" />
- <combo_box.item
- name="Contents"
- label="Contents"
- value="3" />
- <combo_box.item
- name="Original"
- label="Original"
- value="1" />
- </combo_box>
- <spinner
- follows="left|top"
- decimal_digits="0"
- increment="1"
- name="Edit Cost"
- label="Price:"
- label_width="100"
- left="10"
- width="192"
- min_val="1"
- height="19"
- max_val="999999999"
- top_pad="5"/>
- <text
- type="string"
- length="1"
- height="15"
- follows="left|top"
- layout="topleft"
- left_delta="82"
- name="CurrencySymbol"
- top_delta="1"
- width="18">
- L$
- </text>
-
- <!--line_editor
- border_style="line"
- border_thickness="1"
- follows="left|top|right"
- height="16"
- layout="topleft"
- left_pad="5"
- max_length_bytes="25"
- name="EditPrice"
- top_delta="0"
- width="242" /-->
-
- <!--text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left="10"
- name="BaseMaskDebug"
- top="155"
- width="330">
- B:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="OwnerMaskDebug"
- top_delta="0"
- width="270">
- O:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="GroupMaskDebug"
- top_delta="0"
- width="210">
- G:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="EveryoneMaskDebug"
- top_delta="0"
- width="150">
- E:
- </text>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="60"
- name="NextMaskDebug"
- top_delta="0"
- width="90">
- N:
- </text-->
-
-</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_settings.xml b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
index 156bba6c27..08b7a7af05 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory_settings.xml
@@ -4,8 +4,8 @@
can_minimize="true"
can_resize="false"
save_rect="true"
- height="370"
- width="370"
+ height="483"
+ width="483"
name="inventory_settings"
title="INVENTORY SETTINGS">
<icon
@@ -16,7 +16,7 @@
left="18"
mouse_opaque="true"
name="multi_folder_icon"
- top="25"
+ top="20"
width="18" />
<text
type="string"
@@ -40,10 +40,10 @@
font="SansSerifMedium"
left="60"
width="300"
- height="70"
+ height="66"
name="multi_double_click_setting">
<radio_item
- height="20"
+ height="18"
label="Expands &amp; collapses folder"
label_text.text_color="White"
follows="left|top"
@@ -51,24 +51,24 @@
name="0"
width="200"/>
<radio_item
- height="20"
+ height="18"
follows="left|top"
label="Opens a new window"
label_text.text_color="White"
layout="topleft"
left_delta="0"
name="1"
- top_pad ="5"
+ top_pad ="3"
width="200" />
<radio_item
- height="20"
+ height="18"
follows="left|top"
label="Switches view"
label_text.text_color="White"
layout="topleft"
left_delta="0"
name="2"
- top_pad ="5"
+ top_pad ="3"
width="200" />
</radio_group>
<icon
@@ -79,7 +79,7 @@
left="18"
mouse_opaque="true"
name="single_folder_icon"
- top_pad="30"
+ top_pad="19"
width="18" />
<text
type="string"
@@ -103,10 +103,10 @@
font="SansSerifMedium"
left="60"
width="300"
- height="45"
+ height="44"
name="single_double_click_setting">
<radio_item
- height="20"
+ height="18"
label="Stays in current window"
label_text.text_color="White"
follows="left|top"
@@ -114,27 +114,37 @@
name="false"
width="200"/>
<radio_item
- height="20"
+ height="18"
follows="left|top"
label="Opens a new window"
label_text.text_color="White"
layout="topleft"
left_delta="0"
name="true"
- top_pad ="5"
+ top_pad ="3"
width="200" />
</radio_group>
+ <icon
+ follows="top|left"
+ height="15"
+ image_name="Icon_Pointer"
+ layout="topleft"
+ left="20"
+ mouse_opaque="true"
+ name="single_folder_icon"
+ top_pad="20"
+ width="15" />
<text
type="string"
length="1"
follows="left|top|right"
height="13"
layout="topleft"
- left="48"
+ left_pad="13"
name="find_original_txt"
font="SansSerifMedium"
text_color="White"
- top_pad="30"
+ top_delta="1"
width="300">
Clicking on "Show in inventory" or "Find original"
</text>
@@ -146,10 +156,10 @@
font="SansSerifMedium"
left="60"
width="300"
- height="45"
+ height="44"
name="find_original_settings">
<radio_item
- height="20"
+ height="18"
label="Shows item in main inventory window"
label_text.text_color="White"
follows="left|top"
@@ -157,23 +167,136 @@
name="false"
width="200"/>
<radio_item
- height="20"
+ height="18"
follows="left|top"
label="Opens a new single-folder window"
label_text.text_color="White"
layout="topleft"
left_delta="0"
name="true"
- top_pad ="5"
+ top_pad ="3"
width="200" />
</radio_group>
- <button
- height="20"
- label="OK"
- layout="topleft"
- left="140"
- bottom="-20"
- name="ok_btn"
- label_color="White"
- width="90" />
+ <icon
+ follows="top|left"
+ height="18"
+ image_name="Inv_Favorite_Star_Full"
+ layout="topleft"
+ left="18"
+ mouse_opaque="true"
+ name="favorites_icon"
+ top_pad="19"
+ width="18" />
+ <text
+ type="string"
+ length="1"
+ layout="topleft"
+ follows="left|top|right"
+ height="13"
+ left_pad="12"
+ top_delta="2"
+ name="favorites_txt"
+ font="SansSerifMedium"
+ text_color="White"
+ width="300">
+ Favorites
+ </text>
+ <check_box
+ control_name="InventoryFavoritesUseStar"
+ layout="topleft"
+ follows="left|top"
+ top_pad="8"
+ font="SansSerifMedium"
+ left="60"
+ width="300"
+ height="18"
+ label="Star on favorite items"
+ name="favorite_star"
+ label_text.text_color="White"
+ initial_value="false"/>
+ <check_box
+ control_name="InventoryFavoritesUseHollowStar"
+ follows="left|top"
+ top_pad="5"
+ layout="topleft"
+ font="SansSerifMedium"
+ left="60"
+ width="150"
+ height="18"
+ label="Star on folders containing a favorite"
+ name="favorite_hollow_star"
+ label_text.text_color="White"
+ initial_value="false"/>
+ <check_box
+ control_name="InventoryFavoritesColorText"
+ follows="left|top"
+ top_pad="5"
+ layout="topleft"
+ font="SansSerifMedium"
+ left="60"
+ width="150"
+ height="18"
+ label="Colored text"
+ name="favorites_color"
+ label_text.text_color="White"
+ initial_value="false"/>
+ <color_swatch
+ can_apply_immediately="true"
+ follows="left|top"
+ layout="topleft"
+ height="24"
+ label_height="0"
+ left_pad="40"
+ name="favorites_swatch"
+ top_delta="-6"
+ width="44" >
+ <color_swatch.init_callback
+ function="ScriptPref.getUIColor"
+ parameter="InventoryFavoriteColor" />
+ <color_swatch.commit_callback
+ function="ScriptPref.applyUIColor"
+ parameter="InventoryFavoriteColor" />
+ </color_swatch>
+ <icon
+ follows="top|left"
+ height="18"
+ image_name="Inv_Object"
+ layout="topleft"
+ left="18"
+ mouse_opaque="true"
+ name="obj_icon"
+ top_pad="19"
+ width="18" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top|right"
+ height="13"
+ layout="topleft"
+ left_pad="12"
+ top_delta="2"
+ name="single_folder_txt"
+ font="SansSerifMedium"
+ text_color="White"
+ width="300">
+ Pressing return on an avatar attachment
+ </text>
+ <combo_box
+ control_name="InventoryAddAttachmentBehavior"
+ layout="topleft"
+ follows="left|top"
+ top_pad="8"
+ height="24"
+ left="60"
+ name="attach_combo"
+ width="300">
+ <combo_box.item
+ label="Adds attachment (recommended)"
+ name="0"
+ value="0"/>
+ <combo_box.item
+ label="Wear (removes attachment at that point)"
+ name="1"
+ value="1"/>
+ </combo_box>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_joystick.xml b/indra/newview/skins/default/xui/en/floater_joystick.xml
index e6f0420698..623f282305 100644
--- a/indra/newview/skins/default/xui/en/floater_joystick.xml
+++ b/indra/newview/skins/default/xui/en/floater_joystick.xml
@@ -3,9 +3,9 @@
legacy_header_height="18"
height="500"
layout="topleft"
- name="Joystick"
+ name="3Dconnexion Device"
help_topic="Viewerhelp:Joystick_Configuration"
- title="JOYSTICK CONFIGURATION"
+ title="3DCONNEXION DEVICE CONFIGURATION"
width="569">
<floater.string
name="JoystickDisabled">
@@ -22,7 +22,7 @@
width="50"
mouse_opaque="false"
name="joystick_lbl">
- Joystick:
+ Device:
</text>
<combo_box
allow_text_entry="false"
@@ -48,7 +48,7 @@
width="140" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="JoystickAxis2"
decimal_digits="0"
increment="1"
@@ -62,7 +62,7 @@
width="140" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="JoystickAxis0"
decimal_digits="0"
increment="1"
@@ -76,7 +76,7 @@
width="140" />
<spinner
bottom="76"
- height="10"
+ height="10"
control_name="JoystickAxis4"
decimal_digits="0"
increment="1"
@@ -90,7 +90,7 @@
width="140" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="JoystickAxis5"
decimal_digits="0"
increment="1"
@@ -104,7 +104,7 @@
width="140" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="JoystickAxis3"
decimal_digits="0"
increment="1"
@@ -118,7 +118,7 @@
width="140" />
<spinner
bottom="96"
- height="10"
+ height="10"
control_name="JoystickAxis6"
decimal_digits="0"
increment="1"
@@ -141,7 +141,7 @@
width="60" />
<check_box
bottom_delta="0"
- height="10"
+ height="10"
control_name="Cursor3D"
label="3D Cursor"
layout="topleft"
@@ -150,7 +150,7 @@
width="60" />
<check_box
bottom_delta="0"
- height="10"
+ height="10"
control_name="AutoLeveling"
label="Auto Level"
layout="topleft"
@@ -173,7 +173,7 @@
</text>
<check_box
bottom="134"
- height="10"
+ height="10"
control_name="JoystickAvatarEnabled"
halign="center"
label="Avatar"
@@ -183,7 +183,7 @@
width="60" />
<check_box
bottom_delta="0"
- height="10"
+ height="10"
control_name="JoystickBuildEnabled"
halign="center"
label="Build"
@@ -193,7 +193,7 @@
width="60" />
<check_box
bottom_delta="0"
- height="10"
+ height="10"
control_name="JoystickFlycamEnabled"
halign="center"
label="Flycam"
@@ -203,7 +203,7 @@
width="60" />
<stat_view
height="270"
- label="Joystick Monitor"
+ label="Axis Monitor"
layout="topleft"
left="359"
name="axis_view"
@@ -213,7 +213,7 @@
<stat_bar
bar_max="2"
bar_min="-2"
- show_bar="true"
+ show_bar="true"
label="Axis 0"
label_spacing="1"
layout="topleft"
@@ -225,7 +225,7 @@
<stat_bar
bar_max="2"
bar_min="-2"
- show_bar="true"
+ show_bar="true"
label="Axis 1"
label_spacing="1"
layout="topleft"
@@ -234,7 +234,7 @@
<stat_bar
bar_max="2"
bar_min="-2"
- show_bar="true"
+ show_bar="true"
label="Axis 2"
label_spacing="1"
layout="topleft"
@@ -243,7 +243,7 @@
<stat_bar
bar_max="2"
bar_min="-2"
- show_bar="true"
+ show_bar="true"
label="Axis 3"
label_spacing="1"
layout="topleft"
@@ -252,7 +252,7 @@
<stat_bar
bar_max="2"
bar_min="-2"
- show_bar="true"
+ show_bar="true"
label="Axis 4"
label_spacing="1"
layout="topleft"
@@ -262,7 +262,7 @@
bar_max="2"
bar_min="-2"
label="Axis 5"
- show_bar="true"
+ show_bar="true"
label_spacing="1"
layout="topleft"
name="axis5"
@@ -281,7 +281,7 @@
</text>
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="AvatarAxisScale1"
decimal_digits="2"
label_width="0"
@@ -293,7 +293,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="BuildAxisScale1"
decimal_digits="2"
label_width="0"
@@ -305,7 +305,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="FlycamAxisScale1"
decimal_digits="2"
label_width="0"
@@ -328,7 +328,7 @@
</text>
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="AvatarAxisScale2"
decimal_digits="2"
label_width="0"
@@ -340,7 +340,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="BuildAxisScale2"
decimal_digits="2"
label_width="0"
@@ -352,7 +352,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="FlycamAxisScale2"
decimal_digits="2"
label_width="0"
@@ -375,7 +375,7 @@
</text>
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="AvatarAxisScale0"
decimal_digits="2"
label_width="0"
@@ -387,7 +387,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="BuildAxisScale0"
decimal_digits="2"
label_width="0"
@@ -399,7 +399,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="FlycamAxisScale0"
decimal_digits="2"
label_width="0"
@@ -422,7 +422,7 @@
</text>
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="AvatarAxisScale4"
decimal_digits="2"
label_width="0"
@@ -434,7 +434,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="BuildAxisScale4"
decimal_digits="2"
label_width="0"
@@ -446,7 +446,7 @@
width="56" />
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="FlycamAxisScale4"
decimal_digits="2"
label_width="0"
@@ -595,7 +595,7 @@
</text>
<spinner
bottom_delta="0"
- height="10"
+ height="10"
control_name="AvatarAxisDeadZone2"
decimal_digits="2"
increment="0.01"
diff --git a/indra/newview/skins/default/xui/en/floater_lua_debug.xml b/indra/newview/skins/default/xui/en/floater_lua_debug.xml
new file mode 100644
index 0000000000..5efe1c958a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_lua_debug.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_minimize="false"
+ can_resize="true"
+ can_close="true"
+ bevel_style="in"
+ height="220"
+ layout="topleft"
+ name="LUA debug"
+ save_rect="true"
+ title="LUA DEBUG"
+ single_instance="true"
+ width="535">
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ font="SansSerif"
+ height="30"
+ layout="topleft"
+ left="10"
+ left_delta="10"
+ name="editor_path_label"
+ top="10"
+ width="100">
+ LUA string:
+ </text>
+ <check_box
+ control_name="LuaDebugShowSource"
+ follows="right|top"
+ height="15"
+ label="Show source info"
+ layout="topleft"
+ top="10"
+ right ="-70"
+ tool_tip="Show source info in Lua Debug Console output"
+ name="show_script_name"
+ width="70"/>
+ <line_editor
+ border_style="line"
+ border_thickness="1"
+ follows="left|top|right"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ left="10"
+ max_length_bytes="300"
+ name="lua_cmd"
+ select_on_focus="true"
+ top_delta="30"
+ width="435" />
+ <button
+ follows="right|top"
+ height="25"
+ label="Execute"
+ layout="topleft"
+ left_pad="5"
+ name="execute_btn"
+ top_delta="-2"
+ width="75" />
+
+ <text_editor
+ enabled="false"
+ left="10"
+ height="95"
+ layout="topleft"
+ name="result_text"
+ follows="all"
+ max_length="65536"
+ width="515"
+ top_delta="40"
+ word_wrap="true" />
+ <text
+ type="string"
+ length="1"
+ follows="left|bottom"
+ font="SansSerif"
+ height="30"
+ layout="topleft"
+ left="10"
+ name="path_label"
+ top_pad="15"
+ width="100">
+ File Path:
+ </text>
+ <line_editor
+ border_style="line"
+ enabled="false"
+ border_thickness="1"
+ follows="left|bottom|right"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ left_delta="65"
+ max_length_bytes="300"
+ name="script_path"
+ select_on_focus="true"
+ top_delta="-2"
+ width="320" />
+ <button
+ follows="right|bottom"
+ height="25"
+ label="Browse..."
+ label_selected="Browse..."
+ layout="topleft"
+ left_pad="5"
+ name="browse_btn"
+ top_delta="-2"
+ width="70" />
+ <button
+ follows="right|bottom"
+ height="25"
+ label="Run"
+ label_selected="Run"
+ layout="topleft"
+ left_pad="5"
+ name="run_btn"
+ width="50" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_lua_scripts.xml b/indra/newview/skins/default/xui/en/floater_lua_scripts.xml
new file mode 100644
index 0000000000..211cea75d8
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_lua_scripts.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_minimize="false"
+ can_resize="true"
+ can_close="true"
+ bevel_style="in"
+ height="220"
+ min_height="220"
+ layout="topleft"
+ name="LUA scripts"
+ save_rect="true"
+ title="LUA Scripts"
+ single_instance="true"
+ width="555"
+ min_width="555">
+ <scroll_list
+ column_padding="0"
+ draw_stripes="true"
+ draw_heading="true"
+ height="200"
+ left="10"
+ follows="all"
+ layout="topleft"
+ sort_column="script_name"
+ multi_select="true"
+ name="scripts_list"
+ top_pad="10"
+ width="535">
+ <scroll_list.columns
+ label="Name"
+ name="script_name"
+ width="180" />
+ <scroll_list.columns
+ label="Path"
+ name="script_path"/>
+ </scroll_list>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml b/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml
index 57b74b360a..9981e5d893 100644
--- a/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml
+++ b/indra/newview/skins/default/xui/en/floater_new_feature_notification.xml
@@ -17,17 +17,7 @@
New inventory features
</floater.string>
<floater.string name="description_txt_inventory">
-You can now add preview images to inventory items and view a folder in its own window.
-Learn more in this [https://community.secondlife.com/blogs/entry/13637-new-features-inventory-item-preview-and-single-folder-view/ blogpost]
- </floater.string>
- <floater.string name="title_txt_gltf">
-New GLTF PBR materials support
- </floater.string>
- <floater.string name="description_txt_gltf">
-You can now use expanded material support with the ability to import and edit GLTF Physically Based Rendering (PBR) Materials.
-In order to support the addition of the GLTF format, some areas in the viewer may appear darker than usual.
-
-Learn more about [https://wiki.secondlife.com/wiki/PBR_Materials Physically Based Rendering (PBR)]
+You can now mark items and folders as favorites. Favorited items will appear in the Favorites tab of inventory and by default will be highlighted with a star in the main inventory view.
</floater.string>
<text
type="string"
diff --git a/indra/newview/skins/default/xui/en/floater_object_weights.xml b/indra/newview/skins/default/xui/en/floater_object_weights.xml
index 5e4b017590..709fbdd27e 100644
--- a/indra/newview/skins/default/xui/en/floater_object_weights.xml
+++ b/indra/newview/skins/default/xui/en/floater_object_weights.xml
@@ -2,7 +2,7 @@
<floater
can_close="true"
can_tear_off="false"
- height="289"
+ height="372"
help_topic="object_weights"
layout="topleft"
name="object_weights"
@@ -13,6 +13,21 @@
<floater.string
name="nothing_selected"
value="--"/>
+ <floater.string
+ name="lowest_lod"
+ value="Lowest"/>
+ <floater.string
+ name="low_lod"
+ value="Low"/>
+ <floater.string
+ name="medium_lod"
+ value="Medium"/>
+ <floater.string
+ name="high_lod"
+ value="High"/>
+ <floater.string
+ name="multiple_lods"
+ value="Multiple"/>
<text
follows="left|top"
@@ -320,4 +335,97 @@
top_delta="0"
value="Total capacity"
width="130" />
+
+
+ <text
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left="10"
+ name="rendering_info_text"
+ text_color="EmphasisColor"
+ top_pad="10"
+ value="RENDERING INFO"
+ width="180" />
+ <text
+ follows="left|top"
+ halign="right"
+ height="16"
+ layout="topleft"
+ left="10"
+ name="lod_level"
+ top_pad="3"
+ value="--"
+ width="40" />
+ <loading_indicator
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left="34"
+ name="lod_level_loading_indicator"
+ top_delta="0"
+ width="16" />
+ <text
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left_pad="10"
+ name="lod_level_label"
+ top_delta="0"
+ value="LOD (Level of detail)"
+ width="130" />
+ <text
+ follows="left|top"
+ halign="right"
+ height="16"
+ layout="topleft"
+ left="10"
+ name="triangles_shown"
+ top_pad="3"
+ value="--"
+ width="40" />
+ <loading_indicator
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left="34"
+ name="triangles_shown_loading_indicator"
+ top_delta="0"
+ width="16" />
+ <text
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left_pad="10"
+ name="triangles_shown_label"
+ top_delta="0"
+ value="Triangles Shown"
+ width="130" />
+ <text
+ follows="left|top"
+ halign="right"
+ height="16"
+ layout="topleft"
+ left="10"
+ name="pixel_area"
+ top_pad="3"
+ value="--"
+ width="40" />
+ <loading_indicator
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left="34"
+ name="pixel_area_loading_indicator"
+ top_delta="0"
+ width="16" />
+ <text
+ follows="left|top"
+ height="16"
+ layout="topleft"
+ left_pad="10"
+ name="pixel_area_label"
+ top_delta="0"
+ value="Pixel Area"
+ width="130" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_post_process.xml b/indra/newview/skins/default/xui/en/floater_post_process.xml
deleted file mode 100644
index 37339f79c8..0000000000
--- a/indra/newview/skins/default/xui/en/floater_post_process.xml
+++ /dev/null
@@ -1,426 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<floater
- legacy_header_height="18"
- height="400"
- layout="topleft"
- name="Post-Process Floater"
- help_topic="post_process_floater"
- title="POST-PROCESS SETTINGS"
- width="400">
- <tab_container
- follows="left|top"
- height="400"
- layout="topleft"
- left="0"
- name="Post-Process Tabs"
- tab_position="top"
- top="0"
- width="400">
- <panel
- border="true"
- follows="left|top|right|bottom"
- height="400"
- label="Color Filter"
- layout="topleft"
- left="1"
- mouse_opaque="false"
- help_topic="post_process_color_filter_tab"
- name="wmiColorFilterPanel"
- top="0"
- width="398">
- <check_box
- control_name="wmiColorFilterToggle"
- height="16"
- label="Enable"
- layout="topleft"
- left="14"
- name="wmiColorFilterToggle"
- top="4"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiColorFilterBrightnessText"
- top_pad="4"
- width="355">
- Brightness
- </text>
- <slider
- control_name="wmiColorFilterBrightness"
- decimal_digits="2"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="1.0"
- layout="topleft"
- left_delta="4"
- max_val="4"
- name="wmiColorFilterBrightness"
- top_pad="20"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiColorFilterSaturationText"
- top_pad="4"
- width="355">
- Saturation
- </text>
- <slider
- control_name="wmiColorFilterSaturation"
- decimal_digits="2"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="1.0"
- layout="topleft"
- left_delta="4"
- max_val="2"
- min_val="-1"
- name="wmiColorFilterSaturation"
- top_pad="20"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiColorFilterContrastText"
- top_pad="4"
- width="355">
- Contrast
- </text>
- <slider
- control_name="wmiColorFilterContrast"
- decimal_digits="2"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="1.0"
- layout="topleft"
- left_delta="4"
- max_val="4"
- name="wmiColorFilterContrast"
- top_pad="20"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiColorFilterBaseText"
- top_pad="4"
- width="355">
- Contrast Base Color
- </text>
- <slider
- control_name="wmiColorFilterBaseR"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="1.0"
- label="R"
- layout="topleft"
- left_delta="4"
- name="wmiColorFilterBaseR"
- top_pad="20"
- width="200" />
- <slider
- control_name="wmiColorFilterBaseG"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="1.0"
- label="G"
- layout="topleft"
- left_delta="0"
- name="wmiColorFilterBaseG"
- top_pad="10"
- width="200" />
- <slider
- control_name="wmiColorFilterBaseB"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="1.0"
- label="B"
- layout="topleft"
- left_delta="0"
- name="wmiColorFilterBaseB"
- top_pad="10"
- width="200" />
- <slider
- control_name="wmiColorFilterBaseI"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="0.5"
- label="I"
- layout="topleft"
- left_delta="0"
- name="wmiColorFilterBaseI"
- top_pad="10"
- width="200" />
- </panel>
- <panel
- border="true"
- follows="left|top|right|bottom"
- height="400"
- label="Night Vision"
- layout="topleft"
- left_delta="0"
- mouse_opaque="false"
- help_topic="post_process_night_vision_tab"
- name="wmiNightVisionPanel"
- top_delta="-236"
- width="398">
- <check_box
- control_name="wmiNightVisionToggle"
- height="16"
- label="Enable"
- layout="topleft"
- left="14"
- name="wmiNightVisionToggle"
- top="4"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiNightVisionBrightMultText"
- top_pad="5"
- width="355">
- Light Amplification Multiple
- </text>
- <slider
- control_name="wmiNightVisionBrightMult"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="3.0"
- layout="topleft"
- left_delta="4"
- max_val="10"
- min_val="1"
- name="wmiNightVisionBrightMult"
- top_pad="20"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiNightVisionNoiseSizeText"
- top_pad="4"
- width="355">
- Noise Size
- </text>
- <slider
- control_name="wmiNightVisionNoiseSize"
- follows="left"
- height="10"
- initial_value="1"
- layout="topleft"
- left_delta="4"
- max_val="100"
- min_val="1"
- name="wmiNightVisionNoiseSize"
- top_pad="20"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiNightVisionNoiseStrengthText"
- top_pad="4"
- width="355">
- Noise Strength
- </text>
- <slider
- control_name="wmiNightVisionNoiseStrength"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="0.3"
- layout="topleft"
- left_delta="4"
- name="wmiNightVisionNoiseStrength"
- top_pad="20"
- width="200" />
- </panel>
- <panel
- border="true"
- follows="left|top|right|bottom"
- height="400"
- label="Bloom"
- layout="topleft"
- left_delta="0"
- help_topic="post_process_bloom_tab"
- name="wmiBloomPanel"
- top_delta="-236"
- width="398">
- <check_box
- control_name="wmiBloomToggle"
- height="16"
- label="Enable"
- layout="topleft"
- left="14"
- name="wmiBloomToggle"
- top="4"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiBloomExtractText"
- top_pad="5"
- width="355">
- Luminosity Extraction
- </text>
- <slider
- control_name="wmiBloomExtract"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="0.9"
- layout="topleft"
- left_delta="4"
- name="wmiBloomExtract"
- top_pad="20"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiBloomSizeText"
- top_pad="4"
- width="355">
- Bloom Size
- </text>
- <slider
- control_name="wmiBloomSize"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="3.0"
- layout="topleft"
- left_delta="4"
- max_val="20"
- name="wmiBloomSize"
- top_pad="20"
- width="200" />
- <text
- type="string"
- length="1"
- follows="left|top|right"
- font="SansSerif"
- height="16"
- layout="topleft"
- left_delta="-4"
- name="wmiBloomStrengthText"
- top_pad="4"
- width="355">
- Bloom Strength
- </text>
- <slider
- control_name="wmiBloomStrength"
- follows="left"
- height="10"
- increment="0.01"
- initial_value="1.2"
- layout="topleft"
- left_delta="4"
- max_val="10"
- name="wmiBloomStrength"
- top_pad="20"
- width="200" />
- </panel>
- <panel
- border="true"
- follows="left|top|right|bottom"
- height="400"
- label="Extras"
- layout="topleft"
- left_delta="0"
- mouse_opaque="false"
- help_topic="post_process_extras_tab"
- name="Extras"
- top_delta="-236"
- width="398">
- <button
- height="20"
- label="LoadEffect"
- label_selected="LoadEffect"
- layout="topleft"
- left="15"
- name="PPLoadEffect"
- top="13"
- width="100" />
- <button
- height="20"
- label="SaveEffect"
- label_selected="SaveEffect"
- layout="topleft"
- left_delta="0"
- name="PPSaveEffect"
- top_pad="7"
- width="100" />
- <combo_box
- height="18"
- layout="topleft"
- left_delta="120"
- name="PPEffectsCombo"
- top="15"
- width="150" />
- <line_editor
- border_style="line"
- border_thickness="1"
- follows="left|right|bottom"
- font="SansSerif"
- height="20"
- label="Effect Name"
- layout="topleft"
- left_delta="0"
- max_length_bytes="40"
- name="PPEffectNameEditor"
- tab_group="1"
- top_pad="22"
- width="150" />
- </panel>
- </tab_container>
-</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 4b0e0bb221..e7fa839001 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -87,49 +87,49 @@
top="40"
width="658">
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_general.xml"
label="General"
layout="topleft"
help_topic="preferences_general_tab"
name="general" />
<panel
- class="panel_preference_graphics"
+ class="panel_preference_graphics"
filename="panel_preferences_graphics1.xml"
label="Graphics"
layout="topleft"
help_topic="preferences_display_tab"
name="display" />
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_sound.xml"
label="Sound &amp; Media"
layout="topleft"
help_topic="preferences_audio_tab"
name="audio" />
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_chat.xml"
label="Chat"
layout="topleft"
help_topic="preferences_chat_tab"
name="chat" />
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_move.xml"
label="Move &amp; View"
layout="topleft"
help_topic="preferences_move_tab"
name="move" />
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_alerts.xml"
label="Notifications"
layout="topleft"
help_topic="preferences_msgs_tab"
name="msgs" />
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_colors.xml"
label="Colors"
layout="topleft"
@@ -143,14 +143,14 @@
help_topic="preferences_im_tab"
name="im" />
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_setup.xml"
label="Setup"
layout="topleft"
help_topic="preferences_input_tab"
name="input" />
<panel
- class="panel_preference"
+ class="panel_preference"
filename="panel_preferences_advanced.xml"
label="Advanced"
layout="topleft"
@@ -170,6 +170,13 @@
layout="topleft"
help_topic="preferences_controls_tab"
name="controls" />
+ <panel
+ class="panel_preference_game_control"
+ filename="panel_preferences_game_control.xml"
+ label="Game Control"
+ layout="topleft"
+ help_topic="preferences_game_control_tab"
+ name="game_control" />
</tab_container>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_preview_trash.xml b/indra/newview/skins/default/xui/en/floater_preview_trash.xml
index f1c87c8c5a..ebb5cd9251 100644
--- a/indra/newview/skins/default/xui/en/floater_preview_trash.xml
+++ b/indra/newview/skins/default/xui/en/floater_preview_trash.xml
@@ -29,6 +29,8 @@
bevel_style="none"
scroll.reserve_scroll_corner="false">
<folder folder_arrow_image="Folder_Arrow"
+ favorite_image="Inv_Favorite_Star_Full"
+ favorite_content_image="Inv_Favorite_Star_Content"
folder_indentation="8"
item_height="20"
item_top_pad="4"
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_console.xml b/indra/newview/skins/default/xui/en/floater_rlv_console.xml
new file mode 100644
index 0000000000..708055d1b6
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_rlv_console.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ can_resize="true"
+ height="400"
+ layout="topleft"
+ min_height="300"
+ min_width="300"
+ name="rlv_console"
+ title="RLVa console"
+ width="600"
+ >
+ <layout_stack
+ animate="false"
+ bottom="-1"
+ default_tab_group="2"
+ follows="all"
+ left="5"
+ layout="topleft"
+ mouse_opaque="false"
+ name="main_stack"
+ right="-5"
+ orientation="vertical"
+ tab_group="1"
+ top="1"
+ >
+ <layout_panel
+ name="body_panel"
+ height="235">
+ <text_editor
+ follows="all"
+ left="1"
+ right="-1"
+ top="0"
+ length="1"
+ font="Monospace"
+ bottom="-1"
+ ignore_tab="false"
+ layout="topleft"
+ max_length="65536"
+ name="console_output"
+ read_only="true"
+ track_end="true"
+ type="string"
+ word_wrap="true"
+ >
+ </text_editor>
+ </layout_panel>
+
+ <layout_panel
+ height="26"
+ auto_resize="false"
+ name="input_panel">
+ <chat_editor
+ layout="topleft"
+ expand_lines_count="5"
+ follows="left|right|bottom"
+ font="SansSerifSmall"
+ height="20"
+ is_expandable="true"
+ text_tentative_color="TextFgTentativeColor"
+ name="console_input"
+ max_length="1023"
+ spellcheck="true"
+ tab_group="3"
+ bottom_delta="20"
+ left="1"
+ top="1"
+ right="-1"
+ show_emoji_helper="false"
+ wrap="true"
+ />
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_settings_debug.xml b/indra/newview/skins/default/xui/en/floater_settings_debug.xml
index a93be6a18d..0b8190df7e 100644
--- a/indra/newview/skins/default/xui/en/floater_settings_debug.xml
+++ b/indra/newview/skins/default/xui/en/floater_settings_debug.xml
@@ -43,6 +43,20 @@
label="Setting"
name="setting" />
</scroll_list>
+ <button
+ follows="right|bottom"
+ layout="topleft"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Icon_Copy"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ name="copy_btn"
+ tool_tip="Copy to clipboard"
+ top_delta="8"
+ left_pad="10"
+ visible="false"
+ height="20"
+ width="20" />
<text
type="string"
length="1"
@@ -51,12 +65,11 @@
layout="topleft"
name="setting_name_txt"
font="SansSerifSmallBold"
- top_delta="8"
- left_pad="10"
+ left_pad="4"
visible="false"
use_ellipses="true"
text_color="White"
- width="240">
+ width="225">
Debug setting name
</text>
<text_editor
@@ -67,6 +80,7 @@
name="comment_text"
follows="left|top"
width="240"
+ left="320"
top_delta="20"
word_wrap="true" />
<radio_group
@@ -198,4 +212,15 @@
name="hide_default"
width="330">
</check_box>
+ <text_editor
+ read_only="true"
+ visible="false"
+ height="115"
+ layout="topleft"
+ name="llsd_text"
+ follows="left|top"
+ width="240"
+ left="320"
+ top="180"
+ word_wrap="true" />
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml b/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
index 51809793d3..c0d260ef59 100644
--- a/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
+++ b/indra/newview/skins/default/xui/en/floater_voice_chat_volume.xml
@@ -22,7 +22,7 @@
increment="0.025"
initial_value="0.5"
label="Voice Chat"
- label_width="50"
+ label_width="60"
layout="topleft"
left="15"
top="50"
diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml
index 08cc9ae19e..873f542046 100644
--- a/indra/newview/skins/default/xui/en/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_world_map.xml
@@ -109,7 +109,7 @@
</panel>
<panel
follows="right|top"
- height="126"
+ height="150"
top_pad="4"
width="238"
left="1"
@@ -285,6 +285,29 @@
by owner
</text>
+ <check_box
+ name="grid_coords_chk"
+ control_name="MapShowGridCoords"
+ layout="topleft"
+ follows="top|right"
+ top_pad="2"
+ left="3"
+ height="16"
+ width="22"
+ />
+ <text
+ name="grid_coords_label"
+ type="string"
+ layout="topleft"
+ follows="top|right"
+ top_delta="2"
+ left_pad="3"
+ height="16"
+ width="220"
+ halign="left"
+ length="1"
+ >Show grid map coordinates</text>
+
<button
follows="top|right"
height="22"
@@ -455,7 +478,7 @@
<panel
follows="right|top|bottom"
- height="330"
+ height="306"
top_pad="0"
width="238"
name="layout_panel_4">
@@ -576,7 +599,7 @@
draw_stripes="false"
bg_writeable_color="0.75 0.75 0.75 0.15"
follows="all"
- height="145"
+ height="121"
layout="topleft"
left="28"
name="search_results"
diff --git a/indra/newview/skins/default/xui/en/game_control_table_camera_rows.xml b/indra/newview/skins/default/xui/en/game_control_table_camera_rows.xml
new file mode 100644
index 0000000000..ef3d7ee4f7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/game_control_table_camera_rows.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+ <rows
+ enabled="false"
+ name="camera_actions"
+ value="">
+ <columns
+ type="icontext"
+ column="action"
+ font="SansSerif"
+ halign="left"
+ label="Camera"
+ name="action"
+ value="Cam_FreeCam_Off" />
+ </rows>
+ <rows
+ name="advance"
+ value="advance">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera move forward/backward"
+ value="Forward/Backward" />
+ </rows>
+ <rows
+ name="pan"
+ value="pan">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera pan left/right"
+ value="Pan Left/Right" />
+ </rows>
+ <rows
+ name="rise"
+ value="rise">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera rise/fall"
+ value="Rise Up/Down" />
+ </rows>
+ <rows
+ name="pitch"
+ value="pitch">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera adjust pitch"
+ value="Pitch Up/Down" />
+ </rows>
+ <rows
+ name="yaw"
+ value="yaw">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera turn left/right"
+ value="Yaw CCW/CW" />
+ </rows>
+ <rows
+ name="zoom"
+ value="zoom">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera zoom in/out"
+ value="Zoom In/Out" />
+ </rows>
+ <!--
+ <rows
+ name="roll_ccw"
+ value="roll_ccw">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera roll counterclockwise"
+ value="Roll Counterclockwise" />
+ </rows>
+ <rows
+ name="roll_cw"
+ value="roll_cw">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ tool_tip="Camera roll clockwise"
+ value="Roll Clockwise" />
+ </rows>
+ -->
+</contents>
diff --git a/indra/newview/skins/default/xui/en/game_control_table_rows.xml b/indra/newview/skins/default/xui/en/game_control_table_rows.xml
new file mode 100644
index 0000000000..cd6f483782
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/game_control_table_rows.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<contents>
+ <rows
+ enabled="false"
+ name="move_actions"
+ value="">
+ <columns
+ type="icontext"
+ column="action"
+ font="SansSerif"
+ halign="left"
+ label="Move Actions"
+ name="action"
+ value="Move_Walk_Off" />
+ </rows>
+ <rows
+ name="push"
+ value="push">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Forward/Backward" />
+ </rows>
+ <rows
+ name="slide"
+ value="slide">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Strafe" />
+ </rows>
+ <rows
+ name="jump"
+ value="jump">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Jump Up" />
+ </rows>
+ <rows
+ name="turn"
+ value="turn">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Turn" />
+ </rows>
+ <rows
+ name="look"
+ value="look">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Look Up/Down" />
+ </rows>
+ <rows
+ name="stop"
+ value="stop">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Stop" />
+ </rows>
+ <rows
+ name="toggle_run"
+ value="toggle_run">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Run" />
+ </rows>
+ <rows
+ name="toggle_fly"
+ value="toggle_fly">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Fly" />
+ </rows>
+ <rows
+ name="toggle_flycam"
+ value="toggle_flycam">
+ <columns
+ column="action"
+ font="SansSerif"
+ halign="left"
+ name="action"
+ value="Flycam" />
+ </rows>
+</contents>
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
index 99f84fe808..d8ef139d37 100644
--- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
@@ -670,6 +670,22 @@
function="Inventory.DoToSelected"
parameter="ungroup_folder_items" />
</menu_item_call>
+ <menu_item_call
+ label="Add to Favorites"
+ layout="topleft"
+ name="Add to Favorites">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="add_to_favorites" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove from Favorites"
+ layout="topleft"
+ name="Remove from Favorites">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="remove_from_favorites" />
+ </menu_item_call>
<menu
label="Use as default for"
layout="topleft"
@@ -725,6 +741,136 @@
<menu_item_call.on_visible
function="Inventory.CanSetFavoriteFolder" />
</menu_item_call>
+ <menu
+ label="Upload to folder"
+ layout="topleft"
+ name="upload_options">
+ <menu_item_call
+ label="Image..."
+ layout="topleft"
+ name="Upload Image">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_texture" />
+ <menu_item_call.on_enable
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Image,texture" />
+ </menu_item_call>
+ <menu_item_call
+ label="Sound (L$[COST])..."
+ layout="topleft"
+ name="Upload Sound">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_sound" />
+ <menu_item_call.on_enable
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Sound,sound" />
+ </menu_item_call>
+ <menu_item_call
+ label="Animation (L$[COST])..."
+ layout="topleft"
+ name="Upload Animation">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_animation" />
+ <menu_item_call.on_enable
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Animation,animation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Model..."
+ layout="topleft"
+ name="Upload Model">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_model" />
+ <menu_item_call.on_enable
+ function="File.EnableUploadModel" />
+ <menu_item_call.on_visible
+ function="File.VisibleUploadModel"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Material..."
+ layout="topleft"
+ name="Upload Material">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_pbr_material" />
+ <menu_item_call.on_enable
+ function="File.EnableUploadMaterial" />
+ </menu_item_call>
+ <menu_item_call
+ label="Bulk..."
+ layout="topleft"
+ name="Bulk Upload">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_bulk" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Bulk Upload,texture" />
+ </menu_item_call>
+ </menu>
+ <menu
+ label="Use as default for"
+ layout="topleft"
+ name="upload_def">
+ <menu_item_call
+ label="Image uploads"
+ layout="topleft"
+ name="Image uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="def_texture" />
+ <menu_item_call.on_visible
+ function="Inventory.CanSetUploadLocation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Sound uploads"
+ layout="topleft"
+ name="Sound uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="def_sound" />
+ <menu_item_call.on_visible
+ function="Inventory.CanSetUploadLocation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Animation uploads"
+ layout="topleft"
+ name="Animation uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="def_animation" />
+ <menu_item_call.on_visible
+ function="Inventory.CanSetUploadLocation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Model uploads"
+ layout="topleft"
+ name="Model uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="def_model" />
+ <menu_item_call.on_visible
+ function="Inventory.CanSetUploadLocation" />
+ </menu_item_call>
+ <menu_item_call
+ label="PBR material uploads"
+ layout="topleft"
+ name="PBR uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="def_pbr_material" />
+ </menu_item_call>
+ </menu>
<menu_item_separator
layout="topleft"
name="Marketplace Separator" />
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
index 99cee83f4e..fb68193006 100755
--- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
+++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml
@@ -50,6 +50,26 @@
function="Outfit.Thumbnail" />
</menu_item_call>
<menu_item_call
+ label="Add to favorites"
+ layout="topleft"
+ name="favorites_add">
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="favorites_add" />
+ <on_click
+ function="Outfit.Favorite" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove from favorites"
+ layout="topleft"
+ name="favorites_remove">
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="favorites_remove" />
+ <on_click
+ function="Outfit.Favorite" />
+ </menu_item_call>
+ <menu_item_call
label="Edit outfit"
layout="topleft"
name="edit">
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index a72f610abb..6912d41afc 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -951,6 +951,99 @@
function="Inventory.DoToSelected"
parameter="ungroup_folder_items" />
</menu_item_call>
+ <menu_item_call
+ label="Add to Favorites"
+ layout="topleft"
+ name="Add to Favorites">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="add_to_favorites" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove from Favorites"
+ layout="topleft"
+ name="Remove from Favorites">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="remove_from_favorites" />
+ </menu_item_call>
+ <menu
+ label="Upload to folder"
+ layout="topleft"
+ name="upload_options">
+ <menu_item_call
+ label="Image..."
+ layout="topleft"
+ name="Upload Image">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_texture" />
+ <menu_item_call.on_enable
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Image,texture" />
+ </menu_item_call>
+ <menu_item_call
+ label="Sound (L$[COST])..."
+ layout="topleft"
+ name="Upload Sound">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_sound" />
+ <menu_item_call.on_enable
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Sound,sound" />
+ </menu_item_call>
+ <menu_item_call
+ label="Animation (L$[COST])..."
+ layout="topleft"
+ name="Upload Animation">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_animation" />
+ <menu_item_call.on_enable
+ function="File.EnableUpload" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Upload Animation,animation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Model..."
+ layout="topleft"
+ name="Upload Model">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_model" />
+ <menu_item_call.on_enable
+ function="File.EnableUploadModel" />
+ <menu_item_call.on_visible
+ function="File.VisibleUploadModel"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Material..."
+ layout="topleft"
+ name="Upload Material">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_pbr_material" />
+ <menu_item_call.on_enable
+ function="File.EnableUploadMaterial" />
+ </menu_item_call>
+ <menu_item_call
+ label="Bulk..."
+ layout="topleft"
+ name="Bulk Upload">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="upload_bulk" />
+ <menu_item_call.on_visible
+ function="Upload.CalculateCosts"
+ parameter="Bulk Upload,texture" />
+ </menu_item_call>
+ </menu>
<menu
label="Use as default for"
layout="topleft"
@@ -961,7 +1054,7 @@
name="Image uploads">
<menu_item_call.on_click
function="Inventory.FileUploadLocation"
- parameter="texture" />
+ parameter="def_texture" />
</menu_item_call>
<menu_item_call
label="Sound uploads"
@@ -969,7 +1062,7 @@
name="Sound uploads">
<menu_item_call.on_click
function="Inventory.FileUploadLocation"
- parameter="sound" />
+ parameter="def_sound" />
</menu_item_call>
<menu_item_call
label="Animation uploads"
@@ -977,7 +1070,7 @@
name="Animation uploads">
<menu_item_call.on_click
function="Inventory.FileUploadLocation"
- parameter="animation" />
+ parameter="def_animation" />
</menu_item_call>
<menu_item_call
label="Model uploads"
@@ -985,7 +1078,7 @@
name="Model uploads">
<menu_item_call.on_click
function="Inventory.FileUploadLocation"
- parameter="model" />
+ parameter="def_model" />
</menu_item_call>
<menu_item_call
label="PBR material uploads"
@@ -993,7 +1086,7 @@
name="PBR uploads">
<menu_item_call.on_click
function="Inventory.FileUploadLocation"
- parameter="pbr_material" />
+ parameter="def_pbr_material" />
</menu_item_call>
</menu>
<menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
index e249acaccd..d17fbf84b3 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
@@ -138,4 +138,15 @@
function="Inventory.GearDefault.Visible"
parameter="multi_folder_view" />
</menu_item_call>
+ <menu_item_separator/>
+ <menu_item_check
+ label="Inventory settings..."
+ name="inv_settings">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="inventory_settings" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="inventory_settings" />
+ </menu_item_check>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
index 33cf01493d..97f53d3a17 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_view_default.xml
@@ -100,15 +100,4 @@
function="Inventory.GearDefault.Visible"
parameter="single_folder_view" />
</menu_item_check>
- <menu_item_separator/>
- <menu_item_check
- label="Inventory settings..."
- name="inv_settings">
- <menu_item_check.on_check
- function="Floater.Visible"
- parameter="inventory_settings" />
- <menu_item_check.on_click
- function="Floater.Toggle"
- parameter="inventory_settings" />
- </menu_item_check>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_lua_scripts.xml b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml
new file mode 100644
index 0000000000..645fee405d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_lua_scripts.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ name="Scripts">
+ <menu_item_call
+ label="Open Containing Folder"
+ layout="topleft"
+ name="open_folder">
+ <menu_item_call.on_click
+ function="Script.OpenFolder" />
+ </menu_item_call>
+ <menu_item_separator/>
+ <menu_item_call
+ label="Terminate script"
+ layout="topleft"
+ name="terminate">
+ <menu_item_call.on_click
+ function="Script.Terminate" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gallery_sort.xml b/indra/newview/skins/default/xui/en/menu_outfit_gallery_sort.xml
new file mode 100644
index 0000000000..aa4cd1483d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gallery_sort.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu
+ layout="topleft"
+ visible="false"
+ name="Sort Outfit">
+ <menu_item_check
+ label="Sort favorites to top"
+ layout="topleft"
+ visible="true"
+ name="sort_favorites_to_top">
+ <on_click
+ function="Sort.OnSort"
+ parameter="favorites_to_top" />
+ <on_check
+ function="Sort.OnEnable"
+ parameter="favorites_to_top" />
+ </menu_item_check>
+ <menu_item_check
+ label="Sort images to top"
+ layout="topleft"
+ visible="true"
+ name="sort_images_to_top">
+ <on_click
+ function="Sort.OnSort"
+ parameter="images_to_top" />
+ <on_check
+ function="Sort.OnEnable"
+ parameter="images_to_top" />
+ </menu_item_check>
+ <menu_item_check
+ label="Sort by name"
+ layout="topleft"
+ visible="true"
+ name="sort_by_name">
+ <on_click
+ function="Sort.OnSort"
+ parameter="by_name" />
+ <on_check
+ function="Sort.OnEnable"
+ parameter="by_name" />
+ </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
index 8f36c7a00a..e333b05d3e 100644
--- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -50,6 +50,26 @@
function="Gear.Thumbnail" />
</menu_item_call>
<menu_item_call
+ label="Add to favorite outfits"
+ layout="topleft"
+ name="favorites_add">
+ <on_visible
+ function="Gear.OnVisible"
+ parameter="favorites_add" />
+ <on_click
+ function="Gear.Favorite" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove from favorite outfits"
+ layout="topleft"
+ name="favorites_remove">
+ <on_visible
+ function="Gear.OnVisible"
+ parameter="favorites_remove" />
+ <on_click
+ function="Gear.Favorite" />
+ </menu_item_call>
+ <menu_item_call
label="Rename outfit"
layout="topleft"
name="rename">
@@ -89,34 +109,6 @@
function="Gear.OnVisible"
parameter="delete" />
</menu_item_call>
- <menu_item_separator>
- <on_visible
- function="Gear.OnVisible"/>
- </menu_item_separator>
- <menu_item_check
- label="Sort folders always by name"
- layout="topleft"
- name="sort_folders_by_name">
- <on_click
- function="Gear.SortByName" />
- <on_check
- function="CheckControl"
- parameter="OutfitGallerySortByName" />
- </menu_item_check>
- <menu_item_call
- label="Expand all folders"
- layout="topleft"
- name="expand">
- <on_click
- function="Gear.Expand" />
- </menu_item_call>
- <menu_item_call
- label="Collapse all folders"
- layout="topleft"
- name="collapse">
- <on_click
- function="Gear.Collapse" />
- </menu_item_call>
<menu_item_separator/>
<!-- copied (with minor modifications) from menu_inventory_add.xml -->
<!-- *TODO: generate dynamically? -->
@@ -277,4 +269,19 @@
</menu_item_call>
</menu>
<!-- copied from menu_inventory_add.xml -->
+
+ <menu_item_separator/>
+
+ <menu_item_check
+ label="Inventory settings..."
+ layout="topleft"
+ visible="true"
+ name="inventory_settings">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="inventory_settings" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="inventory_settings" />
+ </menu_item_check>
</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_list_sort.xml b/indra/newview/skins/default/xui/en/menu_outfit_list_sort.xml
new file mode 100644
index 0000000000..0a4d1ea877
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_outfit_list_sort.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu
+ layout="topleft"
+ visible="false"
+ name="Sort Outfit">
+ <menu_item_call
+ label="Expand all folders"
+ layout="topleft"
+ name="expand">
+ <on_click
+ function="Sort.Expand" />
+ </menu_item_call>
+ <menu_item_call
+ label="Collapse all folders"
+ layout="topleft"
+ visible="true"
+ name="collapse">
+ <on_click
+ function="Sort.Collapse" />
+ </menu_item_call>
+
+ <menu_item_separator/>
+
+ <menu_item_check
+ label="Sort favorites to top"
+ layout="topleft"
+ name="sort_favorites_to_top">
+ <on_click
+ function="Sort.OnSort"
+ parameter="favorites_to_top" />
+ <on_check
+ function="Sort.OnEnable"
+ parameter="favorites_to_top" />
+ </menu_item_check>
+
+ <menu_item_separator/>
+
+ <menu_item_check
+ label="Show entire outfit in search"
+ layout="topleft"
+ name="show_entire_outfit_in_search">
+ <on_click
+ function="Sort.OnSort"
+ parameter="show_entire_outfit" />
+ <on_check
+ function="Sort.OnEnable"
+ parameter="show_entire_outfit" />
+ </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
index c6805edd63..0d45e7c95c 100644
--- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml
@@ -50,6 +50,26 @@
function="Outfit.Thumbnail" />
</menu_item_call>
<menu_item_call
+ label="Add to favorites"
+ layout="topleft"
+ name="favorites_add">
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="favorites_add" />
+ <on_click
+ function="Outfit.Favorite" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove from favorites"
+ layout="topleft"
+ name="favorites_remove">
+ <on_visible
+ function="Outfit.OnVisible"
+ parameter="favorites_remove" />
+ <on_click
+ function="Outfit.Favorite" />
+ </menu_item_call>
+ <menu_item_call
label="Edit outfit"
layout="topleft"
name="edit">
diff --git a/indra/newview/skins/default/xui/en/menu_settings_gear.xml b/indra/newview/skins/default/xui/en/menu_settings_gear.xml
index 57f4aa8655..96cbac4478 100644
--- a/indra/newview/skins/default/xui/en/menu_settings_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_settings_gear.xml
@@ -24,6 +24,9 @@
<menu_item_call.on_click
function="MyEnvironments.DoApply"
parameter="local" />
+ <menu_item_call.on_enable
+ function="MyEnvironments.CanApply"
+ parameter="local"/>
</menu_item_call>
<menu_item_call
name="Settings Apply Parcel"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 977b225960..86016b3b30 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -19,7 +19,7 @@
label="Inventory..."
name="Inventory"
shortcut="control|I"
- visible="true">
+ visible="true">
<menu_item_check.on_check
function="Floater.Visible"
parameter="inventory" />
@@ -737,8 +737,7 @@
function="Floater.Show"
parameter="snapshot" />
</menu_item_call>
-
-<menu_item_call
+ <menu_item_call
label="360 snapshot"
name="Capture 360"
shortcut="control|alt|shift|s">
@@ -1586,6 +1585,64 @@ function="World.EnvPreset"
parameter="RenderDisablePostProcessing" />
</menu_item_check>
+
+ <menu
+ create_jump_keys="true"
+ label="Selection level of detail"
+ name="Selection level of detail"
+ tear_off="true">
+
+ <menu_item_check
+ label="Default"
+ name="Default lod setting">
+ <menu_item_check.on_check
+ function="Tools.ToolsCheckSelectionLODMode"
+ parameter="default" />
+ <menu_item_check.on_click
+ function="Tools.SelectionLODMode"
+ parameter="default" />
+ </menu_item_check>
+ <menu_item_check
+ label="High"
+ name="High lod setting">
+ <menu_item_check.on_check
+ function="Tools.ToolsCheckSelectionLODMode"
+ parameter="high" />
+ <menu_item_check.on_click
+ function="Tools.SelectionLODMode"
+ parameter="high" />
+ </menu_item_check>
+ <menu_item_check
+ label="Medium"
+ name="Medium lod setting">
+ <menu_item_check.on_check
+ function="Tools.ToolsCheckSelectionLODMode"
+ parameter="medium" />
+ <menu_item_check.on_click
+ function="Tools.SelectionLODMode"
+ parameter="medium" />
+ </menu_item_check>
+ <menu_item_check
+ label="Low"
+ name="Low lod setting">
+ <menu_item_check.on_check
+ function="Tools.ToolsCheckSelectionLODMode"
+ parameter="low" />
+ <menu_item_check.on_click
+ function="Tools.SelectionLODMode"
+ parameter="low" />
+ </menu_item_check>
+ <menu_item_check
+ label="Lowest"
+ name="Lowest lod setting">
+ <menu_item_check.on_check
+ function="Tools.ToolsCheckSelectionLODMode"
+ parameter="lowest" />
+ <menu_item_check.on_click
+ function="Tools.SelectionLODMode"
+ parameter="lowest" />
+ </menu_item_check>
+ </menu>
<menu_item_separator/>
<menu_item_check
@@ -1843,6 +1900,71 @@ function="World.EnvPreset"
</menu>
<menu
create_jump_keys="true"
+ label="RLVa"
+ name="RLVa Main"
+ tear_off="true"
+ visible="true">
+ <menu
+ label="Debug"
+ name="Debug"
+ tear_off="true">
+ <menu_item_check
+ label="Show Top-level RLVa Menu"
+ name="Show Top-level RLVa Menu">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="RLVaTopLevelMenu" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="RLVaTopLevelMenu" />
+ </menu_item_check>
+ <menu_item_separator/>
+ <menu_item_check
+ label="Show Debug Messages"
+ name="Show Debug Messages">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="RestrainedLoveDebug" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="RestrainedLoveDebug" />
+ </menu_item_check>
+ <menu_item_check
+ label="Hide Unset or Duplicate Messages"
+ name="Hide Unset or Duplicate Messages">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="RLVaDebugHideUnsetDuplicate" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="RLVaDebugHideUnsetDuplicate" />
+ </menu_item_check>
+ </menu>
+ <menu_item_separator/>
+ <menu_item_check
+ label="Allow Temporary Attachments"
+ name="Allow Temporary Attachments">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="RLVaEnableTemporaryAttachments" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="RLVaEnableTemporaryAttachments" />
+ </menu_item_check>
+ <menu_item_separator />
+ <menu_item_check
+ label="Console..."
+ name="Console">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="rlv_console" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="rlv_console" />
+ </menu_item_check>
+ </menu>
+ <menu
+ create_jump_keys="true"
label="Advanced"
name="Advanced"
tear_off="true"
@@ -2349,6 +2471,11 @@ function="World.EnvPreset"
parameter="flexible" />
</menu_item_check>
</menu>
+ <menu
+ label="RLVa"
+ name="RLVa Embedded"
+ tear_off="true"
+ visible="true" />
<menu_item_check
label="Use Plugin Read Thread"
name="Use Plugin Read Thread">
@@ -2496,6 +2623,22 @@ function="World.EnvPreset"
visible="false">
<menu
create_jump_keys="true"
+ label="Experimental Features"
+ name="Experimental Features"
+ tear_off="true">
+ <menu_item_check
+ label="GameControl"
+ name="ToggleGameControl">
+ <menu_item_check.on_check
+ function="Advanced.CheckExperiment"
+ parameter="GameControl" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleExperiment"
+ parameter="GameControl" />
+ </menu_item_check>
+ </menu>
+ <menu
+ create_jump_keys="true"
label="Consoles"
name="Consoles"
tear_off="true">
@@ -2588,6 +2731,37 @@ function="World.EnvPreset"
parameter="scene monitor" />
</menu_item_check>
<menu_item_separator/>
+ <menu_item_check
+ label="LUA Debug Console"
+ name="LUA Debug Console">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="lua_debug" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="lua_debug" />
+ <menu_item_check.on_visible
+ function="CheckControl"
+ parameter="LuaFeature" />
+ </menu_item_check>
+ <menu_item_check
+ label="LUA Scripts Info"
+ name="LUA Scripts">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="lua_scripts" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="lua_scripts" />
+ <menu_item_check.on_visible
+ function="CheckControl"
+ parameter="LuaFeature" />
+ </menu_item_check>
+ <menu_item_separator>
+ <menu_item_separator.on_visible
+ function="CheckControl"
+ parameter="LuaFeature"/>
+ </menu_item_separator>
<menu_item_call
label="Region Info to Debug Console"
@@ -3714,6 +3888,13 @@ function="World.EnvPreset"
</menu_item_call>
<menu_item_call
enabled="true"
+ label="Edit Local Paintmap"
+ name="Edit Local Paintmap">
+ <menu_item_call.on_click
+ function="Advanced.TerrainEditLocalPaintMap" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="true"
label="Delete Local Paintmap"
name="Delete Local Paintmap">
<menu_item_call.on_click
diff --git a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
index ee77ef23f0..63d37edf38 100644
--- a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
+++ b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml
@@ -80,6 +80,20 @@
function="Attachment.Profile" />
</menu_item_call>
<menu_item_call
+ label="Add to favorites"
+ layout="topleft"
+ name="favorites_add">
+ <on_click
+ function="Attachment.Favorite" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove from favorites"
+ layout="topleft"
+ name="favorites_remove">
+ <on_click
+ function="Attachment.Favorite" />
+ </menu_item_call>
+ <menu_item_call
label="Show Original"
layout="topleft"
visible="false"
diff --git a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml
index 321e8a0831..9a752a1643 100644
--- a/indra/newview/skins/default/xui/en/menu_wearing_tab.xml
+++ b/indra/newview/skins/default/xui/en/menu_wearing_tab.xml
@@ -31,6 +31,20 @@
function="Wearing.Detach"
parameter="detach"/>
</menu_item_call>
+ <menu_item_call
+ label="Add to favorites"
+ layout="topleft"
+ name="favorites_add">
+ <on_click
+ function="Wearing.Favorite" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove from favorites"
+ layout="topleft"
+ name="favorites_remove">
+ <on_click
+ function="Wearing.Favorite" />
+ </menu_item_call>
<menu_item_separator
layout="topleft"
name="edit_outfit_separator" />
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 805f156e81..5a146904ba 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -1662,7 +1662,7 @@ The new skin will appear after you restart [APP_NAME].
icon="alertmodal.tga"
name="ChangeLanguage"
type="alertmodal">
-Changing language will take effect after you restart [APP_NAME].
+Changing language or time format will take effect after you restart [APP_NAME].
</notification>
<notification
@@ -3129,9 +3129,13 @@ Would you be my friend?
<input name="listname" type="text"/>
<button
default="true"
- index="0"
+ index="1"
name="SetName"
text="OK"/>
+ <button
+ index="0"
+ name="Cancel"
+ text="Cancel"/>
</form>
</notification>
@@ -3160,6 +3164,29 @@ Would you be my friend?
<notification
icon="alertmodal.tga"
+ label="Rename Auto-Replace List"
+ name="RemoveAutoReplaceList"
+ type="alertmodal">
+'[LIST_NAME]' contains [MAP_SIZE] entries.
+
+Are you sure you want to delete this list?
+ <tag>confirm</tag>
+ <form name="form">
+ <button
+ default="true"
+ index="1"
+ name="DeleteList"
+ text="Delete"/>
+ <button
+ default="false"
+ index="0"
+ name="Cancel"
+ text="Cancel"/>
+ </form>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="InvalidAutoReplaceEntry"
type="alertmodal">
The keyword must be a single word, and the replacement may not be empty.
@@ -4618,13 +4645,12 @@ You already have blocked this name.
<notification
icon="alert.tga"
- name="RemoveItemWarn"
+ name="CantModifyContentInNoModTask"
type="alert">
-Though permitted, deleting contents may damage the object. Do you want to delete that item?
+You don't have permission to modify content of this object
<tag>confirm</tag>
<usetemplate
- name="okcancelbuttons"
- notext="Cancel"
+ name="okbutton"
yestext="OK"/>
</notification>
@@ -6532,6 +6558,22 @@ Do you want to replace it with the selected object?
</notification>
<notification
+ icon="alertmodal.tga"
+ name="CantLinkNotecard"
+ type="alertmodal">
+ You must save the notecard before creating a link to it.
+ <tag>fail</tag>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="CantLinkMaterial"
+ type="alertmodal">
+ You must save the material before creating a link to it.
+ <tag>fail</tag>
+ </notification>
+
+ <notification
icon="alert.tga"
label="Do Not Disturb Mode Warning"
name="DoNotDisturbModePay"
@@ -7556,7 +7598,7 @@ Message from [NAME]:
type="notify">
<unique/>
This land has damage enabled.
-You can be hurt here. If you die, you will be teleported to your home location.
+You can be hurt here. If you die, you might be teleported to your home location or to the spawn point.
</notification>
<notification
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index 970c6ad2f5..420759507f 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -180,6 +180,5 @@
mouse_opaque="true"
name="speaking_indicator"
tool_tip="Voice volume"
- visible="true"
width="20" />
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml b/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
index 7902588598..e0b7f71321 100644
--- a/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_conversation_list_item.xml
@@ -91,7 +91,6 @@
left_pad="5"
mouse_opaque="true"
name="speaking_indicator"
- visible="false"
width="20" />
</layout_panel>
</layout_stack>
diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml
index 02e135a2c7..868d54401e 100644
--- a/indra/newview/skins/default/xui/en/panel_group_roles.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel
- height="750"
+ height="770"
label="Members &amp; Roles"
layout="topleft"
left="0"
@@ -18,9 +18,9 @@
<panel.string
name="help_text" />
<tab_container
- border="false"
+ border="false"
follows="left|top|right"
- height="552"
+ height="770"
halign="center"
layout="topleft"
left="0"
@@ -29,16 +29,10 @@
tab_position="top"
tab_height="22"
tab_min_width="90"
- top="0"
- width="304">
+ top="0">
<panel
border="false"
- follows="all"
- height="303"
label="MEMBERS"
- layout="topleft"
- left="0"
- right="-1"
help_topic="roles_members_tab"
name="members_sub_tab"
tool_tip="Members"
@@ -65,16 +59,16 @@ clicking on their names.
name="power_partial_icon" translate="false">
Checkbox_Off
</panel.string>
- <filter_editor
- layout="topleft"
- top="5"
- left="5"
- right="-5"
- height="22"
- search_button_visible="false"
- follows="left|top|right"
- label="Filter Members"
- name="filter_input" />
+ <filter_editor
+ layout="topleft"
+ top="5"
+ left="5"
+ right="-5"
+ height="22"
+ search_button_visible="false"
+ follows="left|top|right"
+ label="Filter Members"
+ name="filter_input" />
<name_list
column_padding="2"
draw_heading="true"
@@ -90,11 +84,11 @@ clicking on their names.
<name_list.columns
label="Member"
name="name"
- relative_width="0.44" />
+ relative_width="0.44" />
<name_list.columns
label="Donation"
name="donated"
- relative_width="0.2" />
+ relative_width="0.2" />
<name_list.columns
label="Status"
name="online"
@@ -118,25 +112,21 @@ clicking on their names.
left_pad="10"
name="member_eject"
width="100" />
- <button
- height="23"
- label="Ban Member(s)"
- follows="top|left"
- left_pad="10"
- name="member_ban"
- width="100" />
+ <button
+ height="23"
+ label="Ban Member(s)"
+ follows="top|left"
+ left_pad="10"
+ name="member_ban"
+ width="100" />
</panel>
<panel
border="false"
- height="303"
label="ROLES"
- layout="topleft"
- left="0"
- right="-1"
help_topic="roles_roles_tab"
name="roles_sub_tab"
class="panel_group_roles_subtab">
- <!-- <button
+ <!--<button
enabled="false"
height="20"
label="Show All"
@@ -145,411 +135,393 @@ clicking on their names.
right="-5"
name="show_all_button"
width="100" />-->
- <panel.string
- name="help_text">
- Roles have a title and an allowed list of Abilities
- that Members can perform. Members can belong to
- one or more Roles. A group can have up to 10 Roles,
- including the Everyone and Owner Roles.
- </panel.string>
- <panel.string
- name="cant_delete_role">
- The &apos;Everyone&apos; and &apos;Owners&apos; Roles are special and can't be deleted.
- </panel.string>
- <panel.string
- name="power_folder_icon" translate="false">
- Inv_FolderClosed
- </panel.string>
- <panel.string
- name="power_all_have_icon" translate="false">
- Checkbox_On
- </panel.string>
- <panel.string
- name="power_partial_icon" translate="false">
- Checkbox_Off
- </panel.string>
- <filter_editor
- layout="topleft"
- top="5"
- left="5"
- right="-5"
- height="22"
- search_button_visible="false"
- follows="left|top|right"
- label="Filter Roles"
- name="filter_input" />
- <scroll_list
- column_padding="0"
- draw_heading="true"
- draw_stripes="false"
- heading_height="23"
- height="132"
- layout="topleft"
- search_column="1"
- left="0"
- follows="left|top|right"
- right="-1"
- name="role_list"
- top_pad="2"
- width="310">
- <scroll_list.columns
- label="Role"
- name="name"
- relative_width="0.45" />
- <scroll_list.columns
- label="Title"
- name="title"
- relative_width="0.45" />
- <scroll_list.columns
- label="#"
- name="members"
- relative_width="0.15" />
- </scroll_list>
- <button
- follows="top|left"
- height="23"
- label="New Role"
- layout="topleft"
- left="0"
- name="role_create"
- width="100" />
- <button
- follows="top|left"
- height="23"
- label="Copy Role"
- layout="topleft"
- left_pad="10"
- name="role_copy"
- width="100" />
- <button
- height="23"
- follows="top|left"
- label="Delete Role"
- layout="topleft"
- left_pad="10"
- name="role_delete"
- width="100" />
- </panel>
+ <panel.string
+ name="help_text">
+ Roles have a title and an allowed list of Abilities
+that Members can perform. Members can belong to
+one or more Roles. A group can have up to 10 Roles,
+including the Everyone and Owner Roles.
+ </panel.string>
+ <panel.string
+ name="cant_delete_role">
+ The &apos;Everyone&apos; and &apos;Owners&apos; Roles are special and can't be deleted.
+ </panel.string>
+ <panel.string
+ name="power_folder_icon" translate="false">
+ Inv_FolderClosed
+ </panel.string>
+ <panel.string
+ name="power_all_have_icon" translate="false">
+ Checkbox_On
+ </panel.string>
+ <panel.string
+ name="power_partial_icon" translate="false">
+ Checkbox_Off
+ </panel.string>
+ <filter_editor
+ layout="topleft"
+ top="5"
+ left="5"
+ right="-5"
+ height="22"
+ search_button_visible="false"
+ follows="left|top|right"
+ label="Filter Roles"
+ name="filter_input" />
+ <scroll_list
+ column_padding="0"
+ draw_heading="true"
+ draw_stripes="false"
+ heading_height="23"
+ height="138"
+ layout="topleft"
+ search_column="1"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ name="role_list"
+ top_pad="2">
+ <scroll_list.columns
+ label="Role"
+ name="name"
+ relative_width="0.45" />
+ <scroll_list.columns
+ label="Title"
+ name="title"
+ relative_width="0.45" />
+ <scroll_list.columns
+ label="#"
+ name="members"
+ relative_width="0.15" />
+ </scroll_list>
+ <button
+ follows="top|left"
+ height="23"
+ label="New Role"
+ layout="topleft"
+ left="0"
+ name="role_create"
+ width="100" />
+ <button
+ follows="top|left"
+ height="23"
+ label="Copy Role"
+ layout="topleft"
+ left_pad="10"
+ name="role_copy"
+ width="100" />
+ <button
+ height="23"
+ follows="top|left"
+ label="Delete Role"
+ layout="topleft"
+ left_pad="10"
+ name="role_delete"
+ width="100" />
+ </panel>
+ <panel
+ border="false"
+ label="ABILITIES"
+ help_topic="roles_actions_tab"
+ name="actions_sub_tab"
+ class="panel_group_actions_subtab"
+ tool_tip="You can view an Ability&apos;s Description and which Roles and Members can execute the Ability.">
+ <panel.string
+ name="help_text">
+ Abilities allow Members in Roles to do specific
+things in this group. There&apos;s a broad variety of Abilities.
+ </panel.string>
+ <panel.string
+ name="power_folder_icon" translate="false">
+ Inv_FolderClosed
+ </panel.string>
+ <panel.string
+ name="power_all_have_icon" translate="false">
+ Checkbox_On
+ </panel.string>
+ <panel.string
+ name="power_partial_icon" translate="false">
+ Checkbox_Off
+ </panel.string>
+ <filter_editor
+ layout="topleft"
+ top="5"
+ left="5"
+ right="-5"
+ height="22"
+ search_button_visible="false"
+ follows="left|top|right"
+ label="Filter Abilities"
+ name="filter_input" />
+ <scroll_list
+ column_padding="0"
+ draw_stripes="true"
+ height="200"
+ follows="left|top|right"
+ layout="topleft"
+ left="0"
+ right="-1"
+ name="action_list"
+ search_column="2"
+ tool_tip="Select an Ability to view more details"
+ top_pad="5">
+ <scroll_list.columns
+ label=""
+ name="icon"
+ width="2" />
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="action" />
+ </scroll_list>
+ </panel>
+ <panel
+ border="false"
+ label="BANNED RESIDENTS"
+ help_topic="roles_banlist_tab"
+ name="banlist_sub_tab"
+ class="panel_group_banlist_subtab"
+ tool_tip="View the banned residents from this group.">
+ <panel.string
+ name="help_text">
+ Any resident on the ban list will be unable to join the group.
+ </panel.string>
+ <panel.string
+ name="ban_count_template">
+ Ban count: [COUNT]/[LIMIT]
+ </panel.string>
+ <name_list
+ column_padding="0"
+ draw_heading="true"
+ height="714"
+ follows="left|top|right"
+ layout="topleft"
+ left="0"
+ right="-1"
+ multi_select="true"
+ name="ban_list"
+ short_names="false"
+ top_pad="5">
+ <name_list.columns
+ label="Resident"
+ name="name"
+ font.name="SANSSERIF_SMALL"
+ font.style="NORMAL"
+ relative_width="0.7" />
+ <name_list.columns
+ label="Date Banned"
+ name="ban_date"
+ relative_width="0.3" />
+ </name_list>
+ <button
+ follows="top|left"
+ height="23"
+ label="Ban Resident(s)"
+ layout="topleft"
+ left="3"
+ name="ban_create"
+ tool_tip="Ban residents from your group"
+ width="120" />
+ <button
+ follows="top|left"
+ height="23"
+ label="Remove Ban(s)"
+ layout="topleft"
+ left_pad="5"
+ name="ban_delete"
+ tool_tip="Unban selected residents from your group"
+ width="120" />
+ <button
+ follows="top|left"
+ height="23"
+ width="23"
+ image_overlay="Refresh_Off"
+ layout="topleft"
+ left_pad="5"
+ name="ban_refresh"
+ tool_tip="Refresh the ban list" />
+ <text
+ type="string"
+ height="18"
+ left_pad="5"
+ follows="top|left"
+ layout="topleft"
+ name="ban_count"
+ width="100">
+ </text>
+ </panel>
+ </tab_container>
<panel
- border="false"
- height="303"
- label="ABILITIES"
+ height="350"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
layout="topleft"
+ follows="top|left|right"
left="0"
right="-1"
- help_topic="roles_actions_tab"
- name="actions_sub_tab"
- class="panel_group_actions_subtab"
- tool_tip="You can view an Ability&apos;s Description and which Roles and Members can execute the Ability."
- width="310">
- <panel.string
- name="help_text">
- Abilities allow Members in Roles to do specific
- things in this group. There&apos;s a broad variety of Abilities.
- </panel.string>
- <panel.string
- name="power_folder_icon" translate="false">
- Inv_FolderClosed
- </panel.string>
- <panel.string
- name="power_all_have_icon" translate="false">
- Checkbox_On
- </panel.string>
- <panel.string
- name="power_partial_icon" translate="false">
- Checkbox_Off
- </panel.string>
- <filter_editor
- layout="topleft"
- top="5"
- left="5"
- right="-5"
- height="22"
- search_button_visible="false"
- follows="left|top|right"
- label="Filter Abilities"
- name="filter_input" />
- <scroll_list
- column_padding="0"
- draw_stripes="true"
- height="200"
- follows="left|top|right"
- layout="topleft"
- left="0"
- right="-1"
- name="action_list"
- search_column="2"
- tool_tip="Select an Ability to view more details"
- top_pad="5"
- width="300">
- <scroll_list.columns
- label=""
- name="icon"
- width="2" />
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="action" />
- </scroll_list>
+ mouse_opaque="false"
+ name="members_footer"
+ top="325"
+ visible="false">
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ top="8"
+ text_color="EmphasisColor"
+ name="static"
+ width="300">
+ Assigned Roles
+ </text>
+ <scroll_list
+ draw_stripes="true"
+ follows="left|top|right"
+ height="150"
+ layout="topleft"
+ left="0"
+ right="-1"
+ name="member_assigned_roles"
+ top_pad="0">
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="role"
+ width="270" />
+ </scroll_list>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ top_pad="5"
+ text_color="EmphasisColor"
+ name="static2"
+ width="285">
+ Allowed Abilities
+ </text>
+ <scroll_list
+ draw_stripes="true"
+ follows="left|top|right"
+ height="150"
+ layout="topleft"
+ left="0"
+ right="-1"
+ name="member_allowed_actions"
+ search_column="2"
+ tool_tip="For details of each allowed ability see the abilities tab"
+ top_pad="0">
+ <scroll_list.columns
+ label=""
+ name="icon"
+ width="2" />
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="action"
+ width="270" />
+ </scroll_list>
</panel>
<panel
- border="false"
- height="303"
- label="BANNED RESIDENTS"
+ height="90"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
layout="topleft"
+ follows="top|left|right"
left="0"
right="-1"
- help_topic="roles_banlist_tab"
- name="banlist_sub_tab"
- class="panel_group_banlist_subtab"
- tool_tip="View the banned residents from this group."
- width="310">
- <panel.string
- name="help_text">
- Any resident on the ban list will be unable to join the group.
- </panel.string>
- <panel.string
- name="ban_count_template">
- Ban count: [COUNT]/[LIMIT]
- </panel.string>
- <name_list
- column_padding="0"
- draw_heading="true"
- height="400"
- follows="left|top|right"
- layout="topleft"
- left="0"
- right="-1"
- multi_select="true"
- name="ban_list"
- short_names="false"
- top_pad="5">
- <name_list.columns
- label="Resident"
- name="name"
- font.name="SANSSERIF_SMALL"
- font.style="NORMAL"
- relative_width="0.7" />
- <name_list.columns
- label="Date Banned"
- name="ban_date"
- relative_width="0.3" />
- </name_list>
- <button
- follows="top|left"
- height="23"
- label="Ban Resident(s)"
- layout="topleft"
- left="3"
- name="ban_create"
- tool_tip="Ban residents from your group"
- width="120" />
- <button
- follows="top|left"
- height="23"
- label="Remove Ban(s)"
- layout="topleft"
- left_pad="5"
- name="ban_delete"
- tool_tip="Unban selected residents from your group"
- width="120" />
- <button
- follows="top|left"
- height="23"
- width="23"
- image_overlay="Refresh_Off"
- layout="topleft"
- left_pad="5"
- name="ban_refresh"
- tool_tip="Refresh the ban list"
- />
- <text
- type="string"
- height="18"
- left_pad="5"
- follows="top|left"
- layout="topleft"
- name="ban_count"
- width="100">
- </text>
+ mouse_opaque="false"
+ name="members_header"
+ top_pad="3"
+ visible="false">
+ <text_editor
+ bg_readonly_color="Transparent"
+ text_readonly_color="EmphasisColor"
+ font="SansSerifSmall"
+ type="string"
+ enabled="false"
+ halign="left"
+ layout="topleft"
+ top_pad="0"
+ follows="left|top|right"
+ left="0"
+ right="-1"
+ height="90"
+ max_length="512"
+ name="member_action_description"
+ word_wrap="true">
+ This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
+ </text_editor>
</panel>
- </tab_container>
- <panel
- height="350"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
- layout="topleft"
- follows="top|left|right"
- left="0"
- right="-1"
- width="313"
- mouse_opaque="false"
- name="members_footer"
- top="325"
- visible="false">
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- top="8"
- text_color="EmphasisColor"
- name="static"
- width="300">
- Assigned Roles
- </text>
- <scroll_list
- draw_stripes="true"
- follows="left|top|right"
- height="150"
+ <panel
+ height="460"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
layout="topleft"
+ follows="top|left|right"
left="0"
right="-1"
- name="member_assigned_roles"
- top_pad="0">
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="role"
- width="270" />
- </scroll_list>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- top_pad="5"
- text_color="EmphasisColor"
- name="static2"
- width="285">
- Allowed Abilities
- </text>
- <scroll_list
- draw_stripes="true"
+ mouse_opaque="false"
+ name="roles_footer"
+ top_delta="0"
+ top="215"
+ visible="false">
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ top="5"
+ name="static"
+ width="300">
+ Role Name
+ </text>
+ <line_editor
+ type="string"
+ height="20"
+ layout="topleft"
+ left="0"
follows="left|top|right"
- height="150"
- layout="topleft"
- left="0"
- right="-1"
- name="member_allowed_actions"
- search_column="2"
- tool_tip="For details of each allowed ability see the abilities tab"
- top_pad="0">
- <scroll_list.columns
- label=""
- name="icon"
- width="2" />
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="action"
- width="270" />
- </scroll_list>
- </panel>
- <panel
- height="90"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
- layout="topleft"
- follows="top|left|right"
- left="0"
- right="-1"
- width="313"
- mouse_opaque="false"
- name="members_header"
- top_pad="3"
- visible="false">
- <text_editor
- bg_readonly_color="Transparent"
- text_readonly_color="EmphasisColor"
- font="SansSerifSmall"
- type="string"
- enabled="false"
- halign="left"
- layout="topleft"
- top_pad="0"
- follows="left|top|right"
- left="0"
- right="-1"
- height="90"
- max_length="512"
- name="member_action_description"
- word_wrap="true">
- This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
- </text_editor>
- </panel>
- <panel
- height="460"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
- layout="topleft"
- follows="top|left|right"
- left="0"
- right="-1"
- width="313"
- mouse_opaque="false"
- name="roles_footer"
- top_delta="0"
- top="209"
- visible="false">
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- top="5"
- name="static"
- width="300">
- Role Name
- </text>
- <line_editor
- type="string"
- height="20"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- max_length_bytes="20"
- name="role_name"
- top_pad="0"
- width="300">
- </line_editor>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- name="static3"
- top_pad="5"
- width="300">
- Role Title
- </text>
- <line_editor
- type="string"
- height="20"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- max_length_bytes="20"
- name="role_title"
- top_pad="0"
- width="300">
- </line_editor>
- <text
+ right="-1"
+ max_length_bytes="20"
+ name="role_name"
+ top_pad="0">
+ </line_editor>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ name="static3"
+ top_pad="5"
+ width="300">
+ Role Title
+ </text>
+ <line_editor
+ type="string"
+ height="20"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ max_length_bytes="20"
+ name="role_title"
+ top_pad="0">
+ </line_editor>
+ <text
type="string"
height="16"
layout="topleft"
@@ -558,192 +530,185 @@ clicking on their names.
name="static2"
top_pad="5"
width="200">
- Description
- </text>
- <text_editor
- type="string"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- max_length="295"
- height="35"
- name="role_description"
- top_pad="0"
- width="300"
- word_wrap="true">
- </text_editor>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- text_color="EmphasisColor"
- name="static4"
- top_pad="5"
- width="300">
- Assigned Members
- </text>
- <name_list
- draw_stripes="true"
- height="128"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- name="role_assigned_members"
- top_pad="0"
- width="300" />
- <check_box
- height="15"
- label="Reveal members"
- left="5"
- layout="topleft"
- name="role_visible_in_list"
- tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group."
- top_pad="4"
- width="300" />
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- text_color="EmphasisColor"
- name="static5"
- top_pad="2"
- width="300">
- Allowed Abilities
- </text>
- <scroll_list
- draw_stripes="true"
- height="140"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- name="role_allowed_actions"
- search_column="2"
- tool_tip="For details of each allowed ability see the abilities tab"
- top_pad="0"
- width="300">
- <scroll_list.columns
- label=""
- name="icon"
- width="2" />
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="action" />
- </scroll_list>
- </panel>
- <panel
- height="90"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
- layout="topleft"
- follows="top|left|right"
- left="0"
- right="-1"
- width="313"
- mouse_opaque="false"
- name="roles_header"
- top_pad="3"
- visible="false">
- <text_editor
- bg_readonly_color="Transparent"
- text_readonly_color="EmphasisColor"
- font="SansSerifSmall"
- type="string"
- enabled="false"
- halign="left"
- layout="topleft"
- top_pad="0"
- follows="left|top|right"
- left="0"
- right="-1"
+ Description
+ </text>
+ <text_editor
+ type="string"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ max_length="295"
+ height="35"
+ name="role_description"
+ top_pad="0"
+ word_wrap="true">
+ </text_editor>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ text_color="EmphasisColor"
+ name="static4"
+ top_pad="5"
+ width="300">
+ Assigned Members
+ </text>
+ <name_list
+ draw_stripes="true"
+ height="128"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ name="role_assigned_members"
+ top_pad="0" />
+ <check_box
+ height="15"
+ label="Reveal members"
+ left="5"
+ layout="topleft"
+ name="role_visible_in_list"
+ tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group."
+ top_pad="4"
+ width="300" />
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ text_color="EmphasisColor"
+ name="static5"
+ top_pad="2"
+ width="300">
+ Allowed Abilities
+ </text>
+ <scroll_list
+ draw_stripes="true"
+ height="140"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ name="role_allowed_actions"
+ search_column="2"
+ tool_tip="For details of each allowed ability see the abilities tab"
+ top_pad="0">
+ <scroll_list.columns
+ label=""
+ name="icon"
+ width="2" />
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="action" />
+ </scroll_list>
+ </panel>
+ <panel
height="90"
- max_length="512"
- name="role_action_description"
- word_wrap="true">
- This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
- </text_editor>
- </panel>
- <panel
- height="424"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
- layout="topleft"
- follows="top|left|right"
- left="0"
- right="-1"
- width="313"
- mouse_opaque="false"
- name="actions_footer"
- top_delta="0"
- top="255"
- visible="false">
- <text_editor
- bg_readonly_color="Transparent"
- text_readonly_color="EmphasisColor"
- font="SansSerifSmall"
- type="string"
- enabled="false"
- halign="left"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
layout="topleft"
- follows="left|top|right"
+ follows="top|left|right"
left="0"
right="-1"
- height="90"
- max_length="512"
- name="action_description"
- top="0"
- word_wrap="true">
- This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
- </text_editor>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- name="static2"
- top_pad="1"
- width="300">
- Roles with this ability
- </text>
- <scroll_list
- height="172"
- layout="topleft"
- follows="left|top|right"
- left="5"
- right="-1"
- name="action_roles"
- top_pad="0"
- width="300" />
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- name="static3"
- top_pad="5"
- width="300">
- Members with this ability
- </text>
- <name_list
- height="122"
- follows="left|top|right"
+ mouse_opaque="false"
+ name="roles_header"
+ top_pad="3"
+ visible="false">
+ <text_editor
+ bg_readonly_color="Transparent"
+ text_readonly_color="EmphasisColor"
+ font="SansSerifSmall"
+ type="string"
+ enabled="false"
+ halign="left"
+ layout="topleft"
+ top_pad="0"
+ follows="left|top|right"
+ left="0"
+ right="-1"
+ height="90"
+ max_length="512"
+ name="role_action_description"
+ word_wrap="true">
+ This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
+ </text_editor>
+ </panel>
+ <panel
+ height="513"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
layout="topleft"
- left="5"
+ follows="top|left|right"
+ left="0"
right="-1"
- name="action_members"
- top_pad="0"
- width="300" />
- </panel>
+ mouse_opaque="false"
+ name="actions_footer"
+ top_delta="0"
+ top="255"
+ visible="false">
+ <text_editor
+ bg_readonly_color="Transparent"
+ text_readonly_color="EmphasisColor"
+ font="SansSerifSmall"
+ type="string"
+ enabled="false"
+ halign="left"
+ layout="topleft"
+ follows="left|top|right"
+ left="0"
+ right="-1"
+ height="90"
+ max_length="512"
+ name="action_description"
+ top="0"
+ word_wrap="true">
+ This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
+ </text_editor>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ name="static2"
+ top_pad="1"
+ width="300">
+ Roles with this ability
+ </text>
+ <scroll_list
+ height="216"
+ layout="topleft"
+ follows="left|top|right"
+ left="5"
+ right="-1"
+ name="action_roles"
+ top_pad="0" />
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ name="static3"
+ top_pad="5"
+ width="300">
+ Members with this ability
+ </text>
+ <name_list
+ height="167"
+ follows="left|top|right"
+ layout="topleft"
+ left="5"
+ right="-1"
+ name="action_members"
+ top_pad="0" />
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
index 73cb9b080f..f5906c17fd 100644
--- a/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
@@ -43,6 +43,16 @@
follows="left|top"
visible="false"
image_name="Inv_Link"/>
+ <icon
+ layout="topleft"
+ follows="left|top"
+ name="fav_icon"
+ left="110"
+ top_pad="-14"
+ height="14"
+ width="14"
+ visible="true"
+ image_name="Inv_Favorite_Star_Full"/>
<panel
background_visible="false"
background_opaque="true"
diff --git a/indra/newview/skins/default/xui/en/panel_landmark_info.xml b/indra/newview/skins/default/xui/en/panel_landmark_info.xml
index e25145dd2a..9cb64e7a13 100644
--- a/indra/newview/skins/default/xui/en/panel_landmark_info.xml
+++ b/indra/newview/skins/default/xui/en/panel_landmark_info.xml
@@ -40,6 +40,10 @@
Information about this location is unavailable due to access restrictions. Please check your permissions with the parcel owner.
</string>
<string
+ name="acquired_date_ampm">
+ [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt]
+ </string>
+ <string
name="acquired_date">
[wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt]
</string>
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 498dab1ef3..6e1e6facbe 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -269,6 +269,22 @@
scroll.reserve_scroll_corner="false">
<folder double_click_override="true"/>
</inventory_panel>
+ <favorites_inventory_panel
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ follows="all"
+ label="FAVORITES"
+ help_topic="recent_inventory_tab"
+ layout="topleft"
+ name="Favorites"
+ show_item_link_overlays="true"
+ preinitialize_views="false"
+ scroll.reserve_scroll_corner="false">
+ <folder double_click_override="true"/>
+ </favorites_inventory_panel>
</tab_container>
</panel>
<panel
diff --git a/indra/newview/skins/default/xui/en/panel_marketplace_listings_inventory.xml b/indra/newview/skins/default/xui/en/panel_marketplace_listings_inventory.xml
index a8a306bea9..9586957694 100644
--- a/indra/newview/skins/default/xui/en/panel_marketplace_listings_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_marketplace_listings_inventory.xml
@@ -21,5 +21,5 @@
border="false"
bevel_style="none"
show_item_link_overlays="true">
- <item allow_wear="false"/>
+ <item marketplace_item="true"/>
</inventory_panel>
diff --git a/indra/newview/skins/default/xui/en/panel_marketplace_listings_listed.xml b/indra/newview/skins/default/xui/en/panel_marketplace_listings_listed.xml
index 0c665fb07e..5f64a5d47a 100644
--- a/indra/newview/skins/default/xui/en/panel_marketplace_listings_listed.xml
+++ b/indra/newview/skins/default/xui/en/panel_marketplace_listings_listed.xml
@@ -20,5 +20,5 @@
border="false"
bevel_style="none"
show_item_link_overlays="true">
- <item allow_wear="false"/>
+ <item marketplace_item="true"/>
</inventory_panel>
diff --git a/indra/newview/skins/default/xui/en/panel_marketplace_listings_unassociated.xml b/indra/newview/skins/default/xui/en/panel_marketplace_listings_unassociated.xml
index 0be405c5b8..ab4d836ba9 100644
--- a/indra/newview/skins/default/xui/en/panel_marketplace_listings_unassociated.xml
+++ b/indra/newview/skins/default/xui/en/panel_marketplace_listings_unassociated.xml
@@ -19,5 +19,5 @@
border="false"
bevel_style="none"
show_item_link_overlays="true">
- <item allow_wear="false"/>
+ <item marketplace_item="true"/>
</inventory_panel>
diff --git a/indra/newview/skins/default/xui/en/panel_marketplace_listings_unlisted.xml b/indra/newview/skins/default/xui/en/panel_marketplace_listings_unlisted.xml
index 58122db7f4..303601e65b 100644
--- a/indra/newview/skins/default/xui/en/panel_marketplace_listings_unlisted.xml
+++ b/indra/newview/skins/default/xui/en/panel_marketplace_listings_unlisted.xml
@@ -20,5 +20,5 @@
border="false"
bevel_style="none"
show_item_link_overlays="true">
- <item allow_wear="false"/>
+ <item marketplace_item="true"/>
</inventory_panel>
diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
index 1a89d07cbb..48f6580d61 100644
--- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
@@ -34,7 +34,6 @@
mouse_opaque="true"
name="chat_zone_indicator"
top="6"
- visible="true"
width="20" />
<button
follows="right"
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
index 6166268206..d49bf19c5d 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_gallery.xml
@@ -35,7 +35,7 @@
</text>
<scroll_container
follows="all"
- height="400"
+ height="429"
width="312"
layout="topleft"
left="4"
@@ -44,49 +44,5 @@
name="gallery_scroll_panel"
opaque="false"
top_pad="0">
- </scroll_container>
- <panel
- background_visible="false"
- follows="bottom|left|right"
- height="28"
- layout="topleft"
- left="4"
- top_pad="0"
- visible="true"
- name="bottom_panel"
- width="312">
- <menu_button
- follows="bottom|left"
- tool_tip="Show additional options"
- height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
- layout="topleft"
- left="0"
- name="options_gear_btn"
- top="1"
- width="31" />
- <icon
- follows="bottom|left|right"
- height="25"
- image_name="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="1"
- name="dummy_icon"
- width="243"/>
- <button
- follows="bottom|right"
- height="25"
- image_hover_unselected="Toolbar_Right_Over"
- image_overlay="TrashItem_Off"
- image_selected="Toolbar_Right_Selected"
- image_unselected="Toolbar_Right_Off"
- layout="topleft"
- left_pad="1"
- name="trash_btn"
- tool_tip="Delete selected outfit"
- width="31"/>
- </panel>
+ </scroll_container>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_list.xml b/indra/newview/skins/default/xui/en/panel_outfits_list.xml
index e8d8e8f3e2..cd4e5ef1f6 100644
--- a/indra/newview/skins/default/xui/en/panel_outfits_list.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_list.xml
@@ -16,7 +16,7 @@
bg_opaque_color="DkGray2"
follows="all"
- height="400"
+ height="428"
layout="topleft"
left="3"
name="outfits_accordion"
@@ -30,48 +30,4 @@
name="no_outfits_msg"
value="You don't have any outfits yet. Try [secondlife:///app/search/all/ Search]"/>
</accordion>
- <panel
- background_visible="false"
- follows="bottom|left|right"
- height="28"
- layout="topleft"
- left="4"
- top_pad="0"
- visible="true"
- name="bottom_panel"
- width="312">
- <menu_button
- follows="bottom|left"
- tool_tip="Show additional options"
- height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
- layout="topleft"
- left="0"
- name="options_gear_btn"
- top="1"
- width="31" />
- <icon
- follows="bottom|left|right"
- height="25"
- image_name="Toolbar_Middle_Off"
- layout="topleft"
- left_pad="1"
- name="dummy_icon"
- width="243"/>
- <button
- follows="bottom|right"
- height="25"
- image_hover_unselected="Toolbar_Right_Over"
- image_overlay="TrashItem_Off"
- image_selected="Toolbar_Right_Selected"
- image_unselected="Toolbar_Right_Off"
- layout="topleft"
- left_pad="1"
- name="trash_btn"
- tool_tip="Delete selected outfit"
- width="31"/>
- </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
index 559917ec0a..10073f0461 100644
--- a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml
@@ -16,7 +16,7 @@
<accordion
fit_parent="true"
follows="all"
- height="400"
+ height="429"
layout="topleft"
left="3"
single_expansion="true"
@@ -62,35 +62,4 @@
</scroll_list>
</accordion_tab>
</accordion>
- <panel
- background_visible="false"
- follows="bottom|left|right"
- height="28"
- layout="topleft"
- left="4"
- name="bottom_panel"
- top_pad="0"
- width="312">
- <menu_button
- follows="bottom|left"
- height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
- layout="topleft"
- left="0"
- name="options_gear_btn"
- tool_tip="Show additional options"
- top="1"
- width="31" />
- <icon
- follows="bottom|left|right"
- height="25"
- image_name="Toolbar_Right_Off"
- layout="topleft"
- left_pad="1"
- name="dummy_icon"
- width="274" />
- </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml
index 9aa0907a38..66cd1cacf1 100644
--- a/indra/newview/skins/default/xui/en/panel_place_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml
@@ -89,6 +89,10 @@
Information about this location is unavailable due to access restrictions. Please check your permissions with the parcel owner.
</string>
<string
+ name="acquired_date_ampm">
+ [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour12,datetime,local]:[min,datetime,local]:[second,datetime,local] [ampm,datetime,local] [year,datetime,local]
+ </string>
+ <string
name="acquired_date">
[wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local]
</string>
diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml
index 4d9a03823e..1005810145 100644
--- a/indra/newview/skins/default/xui/en/panel_places.xml
+++ b/indra/newview/skins/default/xui/en/panel_places.xml
@@ -19,7 +19,7 @@ background_visible="false"
value="VISITED" />
<string
name="favorites_tab_title"
- value="FAVORITES" />
+ value="FAVORITES BAR" />
<string
name="tooltip_trash_items"
value="Remove selected landmark or folder" />
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
index f8801f9c89..b02270dd9e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_controls.xml
@@ -6,7 +6,7 @@
label="Controls"
layout="topleft"
left="102"
- name="controls"
+ name="controls_panel"
top="1"
width="517">
<combo_box
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_game_control.xml b/indra/newview/skins/default/xui/en/panel_preferences_game_control.xml
new file mode 100644
index 0000000000..fb6cc8dc14
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_preferences_game_control.xml
@@ -0,0 +1,449 @@
+<?xml version="1.0" encoding="utf-8"?>
+<panel
+ border="true"
+ follows="all"
+ height="408"
+ label="Game Controls"
+ layout="topleft"
+ left="102"
+ name="game_control_panel"
+ top="1"
+ width="517">
+ <check_box
+ name="game_control_to_server"
+ control_name="GameControlToServer"
+ label="Send GameControl Data to server"
+ layout="topleft"
+ height="15"
+ left="10"
+ top="10"/>
+ <check_box
+ name="game_control_to_agent"
+ control_name="GameControlToAgent"
+ label="GameControl moves avatar and flycam"
+ layout="topleft"
+ height="15"
+ left="10"
+ top="30"/>
+ <check_box
+ name="agent_to_game_control"
+ control_name="AgentToGameControl"
+ label="Avatar actions interpreted as GameControl"
+ layout="topleft"
+ height="15"
+ left="10"
+ top="50"/>
+ <tab_container
+ name="game_control_tabs"
+ layout="topleft"
+ follows="all"
+ top="70"
+ left="2"
+ right="-2"
+ bottom="-32">
+ <panel
+ name="tab_channel_mappings"
+ label="Channel mappings">
+ <scroll_list
+ name="action_table"
+ layout="topleft"
+ follows="all"
+ top="1"
+ left="6"
+ right="-5"
+ bottom="-4"
+ can_sort="false"
+ column_padding="0"
+ multi_select="false"
+ selection_type="header"
+ fg_disable_color="ScrollUnselectedColor">
+ <scroll_list.columns
+ name="action"
+ label="Action"
+ relative_width="0.25" />
+ <scroll_list.columns
+ name="channel"
+ label="Channel"
+ relative_width="0.75" />
+ </scroll_list>
+ </panel>
+ <panel
+ name="tab_device_settings"
+ label="Device settings">
+ <text
+ type="string"
+ name="nodevice_message"
+ layout="topleft"
+ follows="all"
+ halign="center"
+ valign="center"
+ top="1"
+ left="1"
+ right="-1"
+ bottom="-1">No device</text>
+ <panel
+ name="device_selection_panel"
+ layout="topleft"
+ follows="top|left|right"
+ top="1"
+ left="1"
+ right="-1"
+ height="60">
+ <text
+ type="string"
+ name="device_prompt"
+ layout="topleft"
+ follows="top|left"
+ valign="center"
+ top="10"
+ left="2"
+ height="21"
+ width="200">Device to customize:</text>
+ <text
+ type="string"
+ name="single_device"
+ layout="topleft"
+ follows="top|left"
+ valign="center"
+ top="30"
+ left="2"
+ height="21"
+ width="500"/>
+ <combo_box
+ name="device_list"
+ layout="topleft"
+ follows="top|left"
+ top="30"
+ left="2"
+ width="500"/>
+ </panel>
+ <!-- This checkbox should be placed inside the above panel -->
+ <check_box
+ name="show_all_known_devices"
+ label="Show all known devices"
+ layout="topleft"
+ follows="top|left"
+ top_delta="10"
+ left="310"/>
+ <panel
+ name="device_settings"
+ layout="topleft"
+ follows="all"
+ top="61"
+ left="1"
+ right="-1"
+ bottom="-1">
+ <tab_container
+ name="device_settings_tabs"
+ layout="topleft"
+ follows="all"
+ top="1"
+ left="1"
+ right="-1"
+ bottom="-1">
+ <panel
+ name="tab_axis_options"
+ label="Axis Options">
+ <scroll_list
+ name="axis_options"
+ follows="all"
+ top="41"
+ left="1"
+ right="-1"
+ bottom="-1"
+ can_sort="false"
+ column_padding="0"
+ draw_heading="true"
+ multi_select="false"
+ selection_type="header"
+ fg_disable_color="ScrollUnselectedColor">
+ <scroll_list.columns
+ name="axis"
+ label="Axis"
+ relative_width="0.5"/>
+ <scroll_list.columns
+ name="invert"
+ label="Invert"
+ relative_width="0.1"/>
+ <scroll_list.columns
+ name="dead_zone"
+ label="Dead Zone"
+ relative_width="0.2"/>
+ <scroll_list.columns
+ name="offset"
+ label="Offset"
+ relative_width="0.2"/>
+ </scroll_list>
+ </panel>
+ <panel
+ name="tab_axis_mappings"
+ label="Axis Mappings">
+ <scroll_list
+ name="axis_mappings"
+ follows="all"
+ top="1"
+ left="1"
+ right="-1"
+ bottom="-1"
+ can_sort="false"
+ column_padding="0"
+ multi_select="false"
+ selection_type="header"
+ fg_disable_color="ScrollUnselectedColor">
+ <scroll_list.columns relative_width="0.5"/>
+ <scroll_list.columns relative_width="0.5"/>
+ </scroll_list>
+ </panel>
+ <panel
+ name="tab_button_mappings"
+ label="Button Mappings">
+ <scroll_list
+ name="button_mappings"
+ follows="all"
+ top="1"
+ left="1"
+ right="-1"
+ bottom="-1"
+ can_sort="false"
+ column_padding="0"
+ multi_select="false"
+ selection_type="header"
+ fg_disable_color="ScrollUnselectedColor">
+ <scroll_list.columns relative_width="0.5"/>
+ <scroll_list.columns relative_width="0.5"/>
+ </scroll_list>
+ </panel>
+ </tab_container>
+ </panel>
+ </panel>
+ </tab_container>
+ <panel
+ name="reset_to_defaults_panel"
+ layout="topleft"
+ follows="top|left"
+ top="405"
+ height="41"
+ left="1"
+ right="-1">
+ <button
+ layout="topleft"
+ follows="top|left"
+ name="reset_to_defaults"
+ label="Reset to Defaults"
+ top="1"
+ left="8"
+ width="200"/>
+ </panel>
+ <spinner
+ name="numeric_value_editor"
+ decimal_digits="0"
+ increment="1"
+ width="100"
+ height="18"/>
+ <combo_box
+ name="axis_selector"
+ width="250"
+ height="18">
+ <combo_box.item name="axis_0" label="AXIS_0 (Left stick: tilt left/right)"/>
+ <combo_box.item name="axis_1" label="AXIS_1 (Left stick: tilt forward/back)"/>
+ <combo_box.item name="axis_2" label="AXIS_2 (Right stick: tilt left/right)"/>
+ <combo_box.item name="axis_3" label="AXIS_3 (Right stick: tilt forward/back)"/>
+ <combo_box.item name="axis_4" label="AXIS_4 (Left trigger: push/release)"/>
+ <combo_box.item name="axis_5" label="AXIS_5 (Right trigger: push/release)"/>
+ <combo_box.item name="axis_none" label="NONE (No mapping)"/>
+ </combo_box>
+ <combo_box
+ name="analog_channel_selector"
+ width="380"
+ height="18">
+ <combo_box.item
+ label="AXIS_0- (Left stick: tilt right)"
+ name="AXIS_0-"
+ value="AXIS_0-"/>
+ <combo_box.item
+ label="AXIS_0+ (Left stick: tilt left)"
+ name="AXIS_0+"
+ value="AXIS_0+"/>
+ <combo_box.item
+ label="AXIS_1- (Left stick: tilt back)"
+ name="AXIS_1-"
+ value="AXIS_1-"/>
+ <combo_box.item
+ label="AXIS_1+ (Left stick: tilt forward)"
+ name="AXIS_1+"
+ value="AXIS_1+"/>
+ <combo_box.item
+ label="AXIS_2- (Right stick: tilt right)"
+ name="AXIS_2-"
+ value="AXIS_2-"/>
+ <combo_box.item
+ label="AXIS_2+ (Right stick: tilt left)"
+ name="AXIS_2+"
+ value="AXIS_2+"/>
+ <combo_box.item
+ label="AXIS_3- (Right stick: tilt back)"
+ name="AXIS_3-"
+ value="AXIS_3-"/>
+ <combo_box.item
+ label="AXIS_3+ (Right stick: tilt forward)"
+ name="AXIS_3+"
+ value="AXIS_3+"/>
+ <combo_box.item
+ label="AXIS_4- (Left trigger: release)"
+ name="AXIS_4-"
+ value="AXIS_4-"/>
+ <combo_box.item
+ label="AXIS_4+ (Left trigger: push)"
+ name="AXIS_4+"
+ value="AXIS_4+"/>
+ <combo_box.item
+ label="AXIS_5- (Right trigger: release)"
+ name="AXIS_5-"
+ value="AXIS_5-"/>
+ <combo_box.item
+ label="AXIS_5+ (Right trigger: push)"
+ name="AXIS_5+"
+ value="AXIS_5+"/>
+ <combo_box.item
+ label="NONE (No mapping)"
+ name="NONE"
+ value="NONE"/>
+ </combo_box>
+ <combo_box
+ name="binary_channel_selector"
+ width="380"
+ height="18">
+ <combo_box.item
+ label="BUTTON_0 ('A' button)"
+ name="BUTTON_0"
+ value="BUTTON_0"/>
+ <combo_box.item
+ label="BUTTON_1 ('B' button)"
+ name="BUTTON_1"
+ value="BUTTON_1"/>
+ <combo_box.item
+ label="BUTTON_2 ('X' button)"
+ name="BUTTON_2"
+ value="BUTTON_2"/>
+ <combo_box.item
+ label="BUTTON_3 ('Y' button)"
+ name="BUTTON_3"
+ value="BUTTON_3"/>
+ <combo_box.item
+ label="BUTTON_4 (Back button)"
+ name="BUTTON_4"
+ value="BUTTON_4"/>
+ <combo_box.item
+ label="BUTTON_5 (Guide button)"
+ name="BUTTON_5"
+ value="BUTTON_5"/>
+ <combo_box.item
+ label="BUTTON_6 (Home button)"
+ name="BUTTON_6"
+ value="BUTTON_6"/>
+ <combo_box.item
+ label="BUTTON_7 (Left stick)"
+ name="BUTTON_7"
+ value="BUTTON_7"/>
+ <combo_box.item
+ label="BUTTON_8 (Right stick)"
+ name="BUTTON_8"
+ value="BUTTON_8"/>
+ <combo_box.item
+ label="BUTTON_9 (Left shoulder)"
+ name="BUTTON_9"
+ value="BUTTON_9"/>
+ <combo_box.item
+ label="BUTTON_10 (Right shoulder)"
+ name="BUTTON_10"
+ value="BUTTON_10"/>
+ <combo_box.item
+ label="BUTTON_11 (DPad up)"
+ name="BUTTON_11"
+ value="BUTTON_11"/>
+ <combo_box.item
+ label="BUTTON_12 (DPad down)"
+ name="BUTTON_12"
+ value="BUTTON_12"/>
+ <combo_box.item
+ label="BUTTON_13 (DPad left)"
+ name="BUTTON_13"
+ value="BUTTON_13"/>
+ <combo_box.item
+ label="BUTTON_14 (DPad right)"
+ name="BUTTON_14"
+ value="BUTTON_14"/>
+ <combo_box.item
+ label="BUTTON_15 (Miscellaneous 1)"
+ name="BUTTON_15"
+ value="BUTTON_15"/>
+ <combo_box.item
+ label="BUTTON_16 (Paddle 1)"
+ name="BUTTON_16"
+ value="BUTTON_16"/>
+ <combo_box.item
+ label="BUTTON_17 (Paddle 2)"
+ name="BUTTON_17"
+ value="BUTTON_17"/>
+ <combo_box.item
+ label="BUTTON_18 (Paddle 3)"
+ name="BUTTON_18"
+ value="BUTTON_18"/>
+ <combo_box.item
+ label="BUTTON_19 (Paddle 4)"
+ name="BUTTON_19"
+ value="BUTTON_19"/>
+ <combo_box.item
+ label="BUTTON_20 (Touchpad)"
+ name="BUTTON_20"
+ value="BUTTON_20"/>
+ <combo_box.item
+ label="BUTTON_21"
+ name="BUTTON_21"
+ value="BUTTON_21"/>
+ <combo_box.item
+ label="BUTTON_22"
+ name="BUTTON_22"
+ value="BUTTON_22"/>
+ <combo_box.item
+ label="BUTTON_23"
+ name="BUTTON_23"
+ value="BUTTON_23"/>
+ <combo_box.item
+ label="BUTTON_24"
+ name="BUTTON_24"
+ value="BUTTON_24"/>
+ <combo_box.item
+ label="BUTTON_25"
+ name="BUTTON_25"
+ value="BUTTON_25"/>
+ <combo_box.item
+ label="BUTTON_26"
+ name="BUTTON_26"
+ value="BUTTON_26"/>
+ <combo_box.item
+ label="BUTTON_27"
+ name="BUTTON_27"
+ value="BUTTON_27"/>
+ <combo_box.item
+ label="BUTTON_28"
+ name="BUTTON_28"
+ value="BUTTON_28"/>
+ <combo_box.item
+ label="BUTTON_29"
+ name="BUTTON_29"
+ value="BUTTON_29"/>
+ <combo_box.item
+ label="BUTTON_30"
+ name="BUTTON_30"
+ value="BUTTON_30"/>
+ <combo_box.item
+ label="BUTTON_31"
+ name="BUTTON_31"
+ value="BUTTON_31"/>
+ <combo_box.item
+ label="NONE (No mapping)"
+ name="NONE"
+ value="NONE"/>
+ </combo_box>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
index 101c506309..ddddb4855f 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
@@ -91,6 +91,37 @@
name="Traditional Chinese"
value="zh" />
</combo_box>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="15"
+ layout="topleft"
+ left="255"
+ name="time_format_textbox"
+ top="10"
+ width="200">
+ Time Format:
+ </text>
+ <combo_box
+ follows="left|top"
+ height="23"
+ layout="topleft"
+ left="255"
+ max_chars="135"
+ name="time_format_combobox"
+ width="70">
+ <combo_box.item
+ enabled="true"
+ label="1:00 AM"
+ name="12H"
+ value="0" />
+ <combo_box.item
+ enabled="true"
+ label="13:00"
+ name="24H"
+ value="1" />
+ </combo_box>
<text
font="SansSerifSmall"
type="string"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
index 0412466b4f..3b43b08201 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
@@ -113,7 +113,7 @@
control_name="ArrowKeysAlwaysMove"
follows="left|top"
height="20"
- label="Arrow keys always move me"
+ label="Arrow keys always move me while in chat"
layout="topleft"
left_delta="5"
name="arrow_keys_move_avatar_check"
@@ -270,7 +270,7 @@
width="200" />
<button
height="23"
- label="Other Devices"
+ label="3Dconnexion devices"
left="30"
name="joystick_setup_button"
top="30"
diff --git a/indra/newview/skins/default/xui/en/panel_profile_pick.xml b/indra/newview/skins/default/xui/en/panel_profile_pick.xml
index 024120931f..4f441b9b49 100644
--- a/indra/newview/skins/default/xui/en/panel_profile_pick.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile_pick.xml
@@ -200,6 +200,26 @@
<layout_panel
follows="all"
+ layout="bottomleft"
+ left_pad="2"
+ name="set_to_curr_location_btn_lp"
+ auto_resize="false"
+ width="100">
+ <button
+ name="set_to_curr_location_btn"
+ label="Set Location"
+ tool_tip="Set to Current Location"
+ left="0"
+ top="0"
+ height="23"
+ width="100"
+ follows="left|top"
+ layout="topleft"
+ />
+ </layout_panel>
+
+ <layout_panel
+ follows="all"
layout="topleft"
name="util_resizer_right"
auto_resize="true"
diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml
index 6ef1b6e44a..47e1e669d1 100644
--- a/indra/newview/skins/default/xui/en/panel_region_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_general.xml
@@ -33,6 +33,28 @@
unknown
</text>
<text
+ follows="right|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ top_delta="0"
+ right="-100"
+ name="estate_id_lbl"
+ width="80">
+ Estate ID:
+ </text>
+ <line_editor
+ follows="right|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ top_delta="0"
+ name="estate_id"
+ enabled="false"
+ right="-10"
+ initial_value="unknown"
+ width="85" />
+ <text
follows="left|top"
font="SansSerif"
height="20"
@@ -55,6 +77,39 @@
unknown
</text>
<text
+ follows="right|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ top_delta="0"
+ right="-100"
+ name="grid_position_lbl"
+ width="80">
+ Grid Position:
+ </text>
+ <line_editor
+ follows="right|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ right="-55"
+ name="grid_position_x"
+ enabled="false"
+ top_delta="0"
+ default_text="n/a"
+ width="40" />
+ <line_editor
+ follows="right|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ right="-10"
+ name="grid_position_y"
+ enabled="false"
+ top_delta="0"
+ default_text="n/a"
+ width="40" />
+ <text
follows="left|top"
font="SansSerif"
height="20"
diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml
index bd68434aab..34b48574d5 100644
--- a/indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml
+++ b/indra/newview/skins/default/xui/en/panel_settings_sky_sunmoon.xml
@@ -248,29 +248,13 @@
</layout_panel>
<layout_panel
- name="moon_layout"
- border="false"
+ border="true"
bevel_style="in"
+ name="moon_layout"
auto_resize="true"
user_resize="false"
visible="true"
height="400">
- <layout_stack
- name="moon_stack"
- left="5"
- top="5"
- right="-5"
- bottom="-5"
- follows="left|top|right|bottom"
- orientation="vertical">
- <layout_panel
- border="true"
- bevel_style="in"
- auto_resize="true"
- user_resize="false"
- visible="true"
- name="moon_layout"
- height="220">
<text
name="moon_label"
follows="left|top"
@@ -423,9 +407,7 @@
name="moonbeacon"
top_pad="5"
left_delta="-8"/>
-
- </layout_panel>
- </layout_stack>
+
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_settings_water.xml b/indra/newview/skins/default/xui/en/panel_settings_water.xml
index 5e65b0e8a2..36ec0cb3ea 100644
--- a/indra/newview/skins/default/xui/en/panel_settings_water.xml
+++ b/indra/newview/skins/default/xui/en/panel_settings_water.xml
@@ -247,7 +247,7 @@
Reflection Wavelet Scale
</text>
<slider
- decimal_digits="1"
+ decimal_digits="2"
follows="left|top"
increment="0.01"
height="16"
@@ -261,7 +261,7 @@
width="150"
can_edit_text="true"/>
<slider
- decimal_digits="1"
+ decimal_digits="2"
follows="left|top"
increment="0.01"
initial_value="0.7"
@@ -274,7 +274,7 @@
width="150"
can_edit_text="true"/>
<slider
- decimal_digits="1"
+ decimal_digits="2"
follows="left|top"
increment="0.01"
initial_value="0.7"
diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml
index f8040b9a65..0cac1b410f 100644
--- a/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_snapshot_inventory.xml
@@ -60,7 +60,7 @@
name="Large(512x512)"
value="[i512,i512]" />
<combo_box.item
- label="Current Window(512x512)"
+ label="Current Window"
name="CurrentWindow"
value="[i0,i0]" />
<combo_box.item
@@ -119,6 +119,8 @@
type="string"
word_wrap="true">
To save your image as a texture select one of the square formats.
+
+Upload cost: L$[UPLOAD_COST]
</text>
<button
follows="right|bottom"
diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
index 3a7731d235..2fb02af61c 100644
--- a/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/en/panel_snapshot_options.xml
@@ -31,7 +31,7 @@
image_overlay_alignment="left"
image_top_pad="-1"
imgoverlay_label_space="10"
- label="Save to Inventory (L$[AMOUNT])"
+ label="Save to Inventory"
layout="topleft"
left_delta="0"
name="save_to_inventory_btn"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
index c03fac4aad..3e9efb6f8b 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
@@ -64,7 +64,7 @@ width="333">
font="SansSerifSmall"
text_color="EmphasisColor"
width="300"
- height="10"
+ height="13"
follows="top|left|right"
layout="topleft"
left="35"
@@ -94,7 +94,7 @@ width="333">
image_overlay="Edit_Wrench"
label=""
layout="topleft"
- left="265"
+ right="-3"
name="edit_outfit_btn"
tool_tip="Edit this outfit"
top="3"
@@ -108,17 +108,100 @@ width="333">
top="6"
width="24" />
</panel>
- <filter_editor
- height="23"
- follows="left|top|right"
- layout="topleft"
- left="10"
- label="Filter Outfits"
- max_length_chars="300"
- name="Filter"
- search_button_visible="true"
- top_pad="10"
- width="307" />
+ <layout_stack
+ animate="false"
+ border_size="0"
+ follows="left|top|right"
+ height="27"
+ layout="topleft"
+ orientation="horizontal"
+ top_pad="6"
+ left="0"
+ name="top_menu_panel"
+ width="320">
+ <layout_panel
+ auto_resize="true"
+ layout="topleft"
+ name="filter_panel"
+ width="193">
+ <filter_editor
+ text_pad_left="10"
+ follows="left|top|right"
+ font="SansSerifSmall"
+ height="23"
+ layout="topleft"
+ left="10"
+ label="Filter Outfits"
+ max_length_chars="300"
+ name="Filter"
+ search_button_visible="true"
+ tab_group="1"
+ top="3"
+ width="181" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="25"
+ layout="topleft"
+ name="options_gear_btn_panel"
+ width="32">
+ <menu_button
+ follows="bottom|left"
+ tool_tip="Show additional options"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ menu_position="bottomleft"
+ layout="topleft"
+ left="0"
+ name="options_gear_btn"
+ top="0"
+ width="31" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="25"
+ layout="topleft"
+ name="options_sort_btn_panel"
+ width="32">
+ <menu_button
+ follows="bottom|left"
+ tool_tip="Show sorting options"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_sort"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ menu_position="bottomleft"
+ layout="topleft"
+ left="0"
+ name="sorting_menu_btn"
+ top="0"
+ width="31" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="25"
+ layout="topleft"
+ name="trash_btn_panel"
+ width="31">
+ <dnd_button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Right_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Right_Selected"
+ image_unselected="Toolbar_Right_Off"
+ left="0"
+ layout="topleft"
+ name="trash_btn"
+ tool_tip="Delete selected outfit"
+ top="0"
+ width="31"/>
+ </layout_panel>
+ </layout_stack>
<panel
class="panel_outfits_inventory"
filename="panel_outfits_inventory.xml"
@@ -129,7 +212,7 @@ width="333">
visible="false"
left="0"
tab_group="1"
- top_pad="6"
+ top_pad="4"
follows="all" />
<panel
class="panel_outfit_edit"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index 1cb3eca2eb..40a88d4121 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -32,6 +32,10 @@
Owner can:
</panel.string>
<panel.string
+ name="acquiredDateAMPM">
+ [wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour12,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [ampm,datetime,slt] [year,datetime,slt]
+ </panel.string>
+ <panel.string
name="acquiredDate">
[wkday,datetime,slt] [mth,datetime,slt] [day,datetime,slt] [hour,datetime,slt]:[min,datetime,slt]:[second,datetime,slt] [year,datetime,slt]
</panel.string>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index ad68bd8d81..c15409d53f 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -60,6 +60,7 @@ Disk cache: [DISK_CACHE_INFO]
HiDPI display mode: [HIDPI]
</string>
<string name="AboutLibs">
+RestrainedLove API: [RLV_VERSION]
J2C Decoder Version: [J2C_VERSION]
Audio Driver Version: [AUDIO_DRIVER_VERSION]
[LIBCEF_VERSION]
@@ -71,7 +72,7 @@ Voice Server Version: [VOICE_VERSION]
<string name="LocalTime">[month, datetime, local] [day, datetime, local] [year, datetime, local] [hour, datetime, local]:[min, datetime, local]:[second,datetime, local]</string>
<string name="ErrorFetchingServerReleaseNotesURL">Error fetching server release notes URL.</string>
<string name="BuildConfiguration">Build Configuration</string>
-
+
<!-- progress -->
<string name="ProgressRestoring">Restoring...</string>
<string name="ProgressChangingResolution">Changing resolution...</string>
@@ -114,10 +115,10 @@ Voice Server Version: [VOICE_VERSION]
<string name="LoginFailedHeader">Login failed.</string>
<string name="Quit">Quit</string>
<string name="create_account_url">http://join.secondlife.com/?sourceid=[sourceid]</string>
-
+
<string name="AgniGridLabel">Second Life Main Grid (Agni)</string>
<string name="AditiGridLabel">Second Life Beta Test Grid (Aditi)</string>
-
+
<string name="ViewerDownloadURL">http://secondlife.com/download</string>
<string name="LoginFailedViewerNotPermitted">
The viewer you are using can no longer access Second Life. Please visit the following page to download a new viewer:
@@ -209,7 +210,7 @@ If you feel this is an error, please contact support@secondlife.com</string>
<string name="YouHaveBeenDisconnected">You have been disconnected from the region you were in.</string>
<string name="SentToInvalidRegion">You were sent to an invalid region.</string>
<string name="TestingDisconnect">Testing viewer disconnect</string>
-
+
<!-- SLShare: User Friendly Filter Names Translation -->
<string name="BlackAndWhite">Black &amp; White</string>
<string name="Colors1970">1970&apos;s Colors</string>
@@ -222,7 +223,7 @@ If you feel this is an error, please contact support@secondlife.com</string>
<string name="LensFlare">Lens Flare</string>
<string name="Miniature">Miniature</string>
<string name="Toycamera">Toy Camera</string>
-
+
<!-- Tooltip -->
<string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar -->
<string name="TooltipNoName">(no name)</string> <!-- No name on an object -->
@@ -259,10 +260,10 @@ If you feel this is an error, please contact support@secondlife.com</string>
<string name="TooltipOutboxMixedStock">All items in a stock folder must have the same type and permission</string>
<string name="TooltipOutfitNotInInventory">You can only put items or outfits from your personal inventory into "My outfits"</string>
<string name="TooltipCantCreateOutfit">One or more items can't be used inside "My outfits"</string>
-
+
<string name="TooltipDragOntoOwnChild">You can't move a folder into its child</string>
<string name="TooltipDragOntoSelf">You can't move a folder into itself</string>
-
+
<!-- tooltips for Urls -->
<string name="TooltipHttpUrl">Click to view this web page</string>
<string name="TooltipSLURL">Click to view this location's information</string>
@@ -370,7 +371,7 @@ are allowed.
<string name="AssetUploadServerDifficulties">The server is experiencing unexpected difficulties.</string>
<string name="AssetUploadServerUnavaliable">Service not available or upload timeout was reached.</string>
<string name="AssetUploadRequestInvalid">
-Error in upload request. Please visit
+Error in upload request. Please visit
http://secondlife.com/support for help fixing this problem.
</string>
@@ -534,6 +535,8 @@ http://secondlife.com/support for help fixing this problem.
<string name="ChangeYourDefaultAnimations">Change your default animations</string>
<string name="ForceSitAvatar">Force your avatar to sit</string>
<string name="ChangeEnvSettings">Change your environment settings</string>
+ <string name="ScriptBy" value="Script by "/>
+ <string name="ScriptStr" value="Script: "/>
<string name="NotConnected">Not Connected</string>
<string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name -->
@@ -2320,7 +2323,8 @@ For AI Character: Get the closest navigable point to the point provided.
<!-- inventory -->
<string name="InventoryNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/all/[SEARCH_TERM] Search].</string>
- <string name="InventoryNoMatchingRecentItems">Didn't find what you're looking for? Try [secondlife:///app/inventory/filters Show filters].</string>
+ <string name="InventoryNoMatchingRecentItems">Didn't find what you're looking for? Try [secondlife:///app/inventory/filters Show filters].</string>
+ <string name="InventoryNoMatchingFavorites">You haven't marked any items as favorites.</string>
<string name="PlacesNoMatchingItems">To add a place to your landmarks, click the star to the right of the location name.</string>
<string name="FavoritesNoMatchingItems">To add a place to your favorites, click the star to the right of the location name, then save the landmark to "Favorites bar".</string>
<string name="MarketplaceNoListing">You have no listings yet.</string>
@@ -2503,7 +2507,7 @@ If you continue to receive this message, please contact Second Life support for
<string name="InvFolder Materials">Materials</string>
<!-- are used for Friends and Friends/All folders in Inventory "Calling cards" folder. See EXT-694-->
- <string name="InvFolder Friends">Friends</string>
+ <string name="InvFolder Friends">Friends</string>
<string name="InvFolder All">All</string>
<string name="no_attachments">No attachments worn</string>
@@ -2672,7 +2676,7 @@ If you continue to receive this message, please contact Second Life support for
<string name="UploadFailed">File upload failed: </string>
<string name="ObjectOutOfRange">Script (object out of range)</string>
<string name="ScriptWasDeleted">Script (deleted from inventory)</string>
-
+
<!-- god tools -->
<string name="GodToolsObjectOwnedBy">Object [OBJECT] owned by [OWNER]</string>
@@ -3719,6 +3723,10 @@ Please reinstall viewer from https://secondlife.com/support/downloads/ and cont
<string name="inventory_folder_offered-im">
Inventory folder '[ITEM_NAME]' offered
</string>
+ <string name="bot_warning">
+ You are chatting with a bot, [NAME]. Do not share any personal information.
+Learn more at https://second.life/scripted-agents.
+ </string>
<string name="share_alert">
Drag items from inventory here
</string>
@@ -3851,7 +3859,7 @@ Please reinstall viewer from https://secondlife.com/support/downloads/ and cont
<string name="uploading_costs">Uploading costs L$ [AMOUNT]</string>
<string name="this_costs">This costs L$ [AMOUNT]</string>
-
+
<string name="buying_selected_land">This land costs</string>
<string name="this_object_costs">This item costs</string>
<string name="giving">You want to give</string>
@@ -3932,7 +3940,7 @@ Abuse Report</string>
<string name="New Daycycle">New Daycycle</string>
<string name="New Water">New Water</string>
<string name="New Sky">New Sky</string>
-
+
<string name="/bow">/bow</string>
<string name="/clap">/clap</string>
@@ -4014,7 +4022,7 @@ Please check http://status.secondlifegrid.net to see if there is a known problem
<string name="Accounting">Accounting</string>
<string name="Notices">Notices</string>
<string name="Chat">Chat</string>
-
+
<!-- SL Membership -->
<string name="BaseMembership">Base</string>
<string name="PremiumMembership">Premium</string>
@@ -4029,6 +4037,10 @@ Please check http://status.secondlifegrid.net to see if there is a known problem
<string name="DeleteItem">Delete selected item?</string>
<string name="EmptyOutfitText">There are no items in this outfit</string>
+ <string name="OutfitNotFound" value="Couldn't find outfit "/>
+ <string name="OutfitNotAdded" value="Can't add to COF outfit "/>
+ <string name="OutfitNotReplaced" value="Can't replace COF with outfit "/>
+ <string name="SystemFolderNotWorn" value="Can't wear system folder "/>
<!-- External editor status codes -->
<string name="ExternalEditorNotSet">Select an editor by setting the environment variable LL_SCRIPT_EDITOR or the ExternalEditor setting.
@@ -4180,7 +4192,7 @@ Try enclosing path to the editor with double quotes.
<!-- commands -->
- <string
+ <string
name="Command_360_Capture_Label">360 snapshot</string>
<string name="Command_AboutLand_Label">About land</string>
<string name="Command_Appearance_Label">Outfits</string>
@@ -4215,7 +4227,7 @@ name="Command_360_Capture_Label">360 snapshot</string>
<string name="Command_FavoriteFolder_Label">Favorite folder</string>
<string name="Command_ResyncAnimations_Label">Resync animations</string>
- <string
+ <string
name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>
<string name="Command_AboutLand_Tooltip">Information about the land you're visiting</string>
<string name="Command_Appearance_Tooltip">Change your avatar</string>
@@ -4282,7 +4294,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>
<!-- Spell check settings floater -->
<string name="UserDictionary">[User]</string>
-
+
<!-- Experience Tools strings -->
<string name="experience_tools_experience">Experience</string>
<string name="ExperienceNameNull">(no experience)</string>
@@ -4318,7 +4330,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>
<!-- PBR Materials -->
<string name="Material Texture Name Header">Textures present this material: </string>
-
+
<!-- Conversation log messages -->
<string name="logging_calls_disabled_log_empty">
Conversations are not being logged. To begin keeping a log, choose "Save: Log only" or "Save: Log and transcripts" under Preferences > Chat.
@@ -4341,7 +4353,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>
<string name="Default">Default</string>
<string name="none_paren_cap">(None)</string>
<string name="no_limit">No limit</string>
-
+
<string name="Mav_Details_MAV_FOUND_DEGENERATE_TRIANGLES">
The physics shape contains triangles which are too small. Try simplifying the physics model.
</string>
@@ -4396,5 +4408,31 @@ and report the problem.
<string name="NotAvailableOnPlatform">Not available on this platform</string>
<string name="NowPlaying">Now Playing</string>
<string name="GridInfoTitle">GRID INFO</string>
+ <!-- RLVa -->
+ <string name="RlvConsoleDisable">RLVa is disabled</string>
+ <string name="RlvConsoleInvalidCmd">Invalid command</string>
+ <string name="RlvConsoleExecuted">INFO</string>
+ <string name="RlvConsoleFailed">ERR</string>
+ <string name="RlvConsoleRetained">RET</string>
+ <string name="RlvDebugExecuted">executed</string>
+ <string name="RlvDebugFailed">failed</string>
+ <string name="RlvDebugRetained">retained</string>
+ <string name="RlvReturnCodeUnset">unset</string>
+ <string name="RlvReturnCodeDuplicate">duplicate</string>
+ <string name="RlvReturnCodeDelayed">delayed</string>
+ <string name="RlvReturnCodeDeprecated">deprecated</string>
+ <string name="RlvReturnCodeSyntax">thingy error</string>
+ <string name="RlvReturnCodeOption">invalid option</string>
+ <string name="RlvReturnCodeParam">invalid param</string>
+ <string name="RlvReturnCodeLock">locked command</string>
+ <string name="RlvReturnCodeDisabled">disabled command</string>
+ <string name="RlvReturnCodeUnknown">unknown command</string>
+ <string name="RlvReturnCodeNoSharedRoot">missing #RLV</string>
+ <string name="RlvReturnCodeDeprecatedAndDisabled">deprecated and disabled</string>
+ <string name="RlvReturnCodeNoBehaviour">no active behaviours</string>
+ <string name="RlvReturnCodeUnheldBehaviour">base behaviour not held</string>
+ <string name="RlvReturnCodeBlocked">blocked object</string>
+ <string name="RlvReturnCodeThrottled">throttled</string>
+ <string name="RlvReturnCodeNoProcessor">no command processor found</string>
</strings>
diff --git a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
index cf995e5833..180071a321 100644
--- a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
+++ b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml
@@ -37,6 +37,5 @@
right="-3"
mouse_opaque="true"
name="speaking_indicator"
- visible="true"
- width="20" />
+ width="20" />
</conversation_view_participant>
diff --git a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
index b598bbccd8..50c5285e04 100644
--- a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
+++ b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<folder_view_item
folder_arrow_image="Folder_Arrow"
+ favorite_image="Inv_Favorite_Star_Full"
+ favorite_content_image="Inv_Favorite_Star_Content"
folder_indentation="8"
item_height="20"
item_top_pad="4"
diff --git a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
index 27ec6ded81..865c145022 100644
--- a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
+++ b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<inbox_folder_view_folder
folder_arrow_image="Folder_Arrow"
+ favorite_image="Inv_Favorite_Star_Full"
+ favorite_content_image="Inv_Favorite_Star_Content"
folder_indentation="8"
item_height="20"
item_top_pad="4"
diff --git a/indra/newview/skins/default/xui/en/widgets/output_monitor.xml b/indra/newview/skins/default/xui/en/widgets/output_monitor.xml
index 788c733ca8..10e39fa030 100644
--- a/indra/newview/skins/default/xui/en/widgets/output_monitor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/output_monitor.xml
@@ -10,4 +10,5 @@
image_level_3="VoicePTT_Lvl3"
mouse_opaque="false"
name="output_monitor"
+ visible="false"
/>
diff --git a/indra/newview/skins/default/xui/en/widgets/person_view.xml b/indra/newview/skins/default/xui/en/widgets/person_view.xml
index 82dbdf0dab..e07f340be1 100644
--- a/indra/newview/skins/default/xui/en/widgets/person_view.xml
+++ b/indra/newview/skins/default/xui/en/widgets/person_view.xml
@@ -111,7 +111,6 @@
right="-3"
mouse_opaque="true"
name="speaking_indicator"
- visible="false"
width="20" />
</person_view>
diff --git a/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml
index b5cf57ade7..c9eea9a58e 100644
--- a/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/es/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
Guardar una imagen en el inventario cuesta [UPLOAD_COST] L$. Para guardar una imagen como una textura, selecciona uno de los formatos cuadrados.
</text>
<combo_box label="Resolución" name="texture_size_combo">
- <combo_box.item label="Ventana actual (512 × 512)" name="CurrentWindow"/>
+ <combo_box.item label="Ventana actual" name="CurrentWindow"/>
<combo_box.item label="Pequeña (128x128)" name="Small(128x128)"/>
<combo_box.item label="Mediana (256x256)" name="Medium(256x256)"/>
<combo_box.item label="Grande (512x512)" name="Large(512x512)"/>
diff --git a/indra/newview/skins/default/xui/es/panel_snapshot_options.xml b/indra/newview/skins/default/xui/es/panel_snapshot_options.xml
index 4eb9ecf28f..f3119c739e 100644
--- a/indra/newview/skins/default/xui/es/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/es/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="Guardar en disco" name="save_to_computer_btn"/>
- <button label="Guardar en inventario (L$[AMOUNT])" name="save_to_inventory_btn"/>
+ <button label="Guardar en inventario" name="save_to_inventory_btn"/>
<button label="Compartir en los comentarios de Mi perfil" name="save_to_profile_btn"/>
<button label="Compartir en Facebook" name="send_to_facebook_btn"/>
<button label="Compartir en Twitter" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml
index c6c0e9e77d..8515108943 100644
--- a/indra/newview/skins/default/xui/es/strings.xml
+++ b/indra/newview/skins/default/xui/es/strings.xml
@@ -29,7 +29,6 @@ Distancia de dibujo: [DRAW_DISTANCE]m
Ancho de banda: [NET_BANDWITH]kbit/s
Factor LOD: [LOD_FACTOR]
Calidad de renderización: [RENDER_QUALITY]
-Modelo de iluminación avanzado: [GPU_SHADERS]
Memoria de textura: [TEXTURE_MEMORY]MB</string>
<string name="AboutOSXHiDPI">Modo de visualización HiDPi: [HIDPI]</string>
<string name="AboutLibs">Versión de descodificador J2C: [J2C_VERSION]
@@ -1585,6 +1584,10 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE].</string>
<string name="conference-title-incoming">Conferencia con [AGENT_NAME]</string>
<string name="inventory_item_offered-im">Ãtem del inventario '[ITEM_NAME]' ofrecido</string>
<string name="inventory_folder_offered-im">Carpeta del inventario '[ITEM_NAME]' ofrecida</string>
+ <string name="bot_warning">
+Estás conversando con un bot, [NAME]. No compartas información personal.
+Más información en https://second.life/scripted-agents.
+ </string>
<string name="share_alert">Arrastra los ítems desde el invenbtario hasta aquí</string>
<string name="facebook_post_success">Has publicado en Facebook.</string>
<string name="flickr_post_success">Has publicado en Flickr.</string>
diff --git a/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml
index 3cf64583d2..a560ff8d5e 100644
--- a/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
L&apos;enregistrement d&apos;une image dans l&apos;inventaire coûte [UPLOAD_COST] L$. Pour enregistrer votre image sous forme de texture, sélectionnez un format carré.
</text>
<combo_box label="Résolution" name="texture_size_combo">
- <combo_box.item label="Fenêtre actuelle (512x512)" name="CurrentWindow"/>
+ <combo_box.item label="Fenêtre actuelle" name="CurrentWindow"/>
<combo_box.item label="Petite (128 x 128)" name="Small(128x128)"/>
<combo_box.item label="Moyenne (256 x 256)" name="Medium(256x256)"/>
<combo_box.item label="Grande (512 x 512)" name="Large(512x512)"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml b/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml
index bdedb9162f..52fa318f8e 100644
--- a/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/fr/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="Enreg. sur le disque" name="save_to_computer_btn"/>
- <button label="Enreg. dans l&apos;inventaire ([AMOUNT] L$)" name="save_to_inventory_btn"/>
+ <button label="Enreg. dans l&apos;inventaire" name="save_to_inventory_btn"/>
<button label="Partager sur le flux de profil" name="save_to_profile_btn"/>
<button label="Partager sur Facebook" name="send_to_facebook_btn"/>
<button label="Partager sur Twitter" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml
index 737b570e98..c0f990d86b 100644
--- a/indra/newview/skins/default/xui/fr/strings.xml
+++ b/indra/newview/skins/default/xui/fr/strings.xml
@@ -32,7 +32,6 @@ Distance de dessin : [DRAW_DISTANCE]m
Bande passante : [NET_BANDWITH] kbit/s
Facteur LOD (niveau de détail) : [LOD_FACTOR]
Qualité de rendu : [RENDER_QUALITY]
-Modèle d’éclairage avancé : [GPU_SHADERS]
Mémoire textures : [TEXTURE_MEMORY] Mo</string>
<string name="AboutOSXHiDPI">Mode d'affichage HiDPI : [HIDPI]</string>
<string name="AboutLibs">J2C Decoder Version: [J2C_VERSION]
@@ -1615,6 +1614,10 @@ Si ce message persiste, veuillez aller sur la page [SUPPORT_SITE].</string>
<string name="conference-title-incoming">Conférence avec [AGENT_NAME]</string>
<string name="inventory_item_offered-im">Objet de l’inventaire [ITEM_NAME] offert</string>
<string name="inventory_folder_offered-im">Dossier de l’inventaire [ITEM_NAME] offert</string>
+ <string name="bot_warning">
+Vous discutez avec un bot, [NAME]. Ne partagez pas d’informations personnelles.
+En savoir plus sur https://second.life/scripted-agents.
+ </string>
<string name="share_alert">Faire glisser les objets de l'inventaire ici</string>
<string name="facebook_post_success">Vous avez publié sur Facebook.</string>
<string name="flickr_post_success">Vous avez publié sur Flickr.</string>
diff --git a/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml
index 75b5d64660..21b65e8e69 100644
--- a/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/it/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
Salvare un&apos;immagine nell&apos;inventario costa L$[UPLOAD_COST]. Per salvare l&apos;immagine come texture, selezionare uno dei formati quadrati.
</text>
<combo_box label="Risoluzione" name="texture_size_combo">
- <combo_box.item label="Finestra corrente (512x512)" name="CurrentWindow"/>
+ <combo_box.item label="Finestra corrente" name="CurrentWindow"/>
<combo_box.item label="Piccola (128x128)" name="Small(128x128)"/>
<combo_box.item label="Media (256x256)" name="Medium(256x256)"/>
<combo_box.item label="Grande (512x512)" name="Large(512x512)"/>
diff --git a/indra/newview/skins/default/xui/it/panel_snapshot_options.xml b/indra/newview/skins/default/xui/it/panel_snapshot_options.xml
index 50fb3d39fa..7fce171326 100644
--- a/indra/newview/skins/default/xui/it/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/it/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="Salva sul disco" name="save_to_computer_btn"/>
- <button label="Salva nell&apos;inventario (L$[AMOUNT])" name="save_to_inventory_btn"/>
+ <button label="Salva nell&apos;inventario" name="save_to_inventory_btn"/>
<button label="Condividi sul feed del profilo" name="save_to_profile_btn"/>
<button label="Condividi su Facebook" name="send_to_facebook_btn"/>
<button label="Condividi su Twitter" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml
index 69381ef00e..4bd1285f2d 100644
--- a/indra/newview/skins/default/xui/it/strings.xml
+++ b/indra/newview/skins/default/xui/it/strings.xml
@@ -31,7 +31,6 @@ Distanza visualizzazione: [DRAW_DISTANCE]m
Larghezza banda: [NET_BANDWITH]kbit/s
Fattore livello di dettaglio: [LOD_FACTOR]
Qualità di rendering: [RENDER_QUALITY]
-Modello illuminazione avanzato: [GPU_SHADERS]
Memoria texture: [TEXTURE_MEMORY]MB</string>
<string name="AboutOSXHiDPI">Modalità display HiDPI: [HIDPI]</string>
<string name="AboutLibs">J2C Versione decoder: [J2C_VERSION]
@@ -1587,6 +1586,10 @@ Se il messaggio persiste, contatta [SUPPORT_SITE].</string>
<string name="conference-title-incoming">Chiamata in conferenza con [AGENT_NAME]</string>
<string name="inventory_item_offered-im">Offerto oggetto di inventario &quot;[ITEM_NAME]&quot;</string>
<string name="inventory_folder_offered-im">Offerta cartella di inventario &quot;[ITEM_NAME]&quot;</string>
+ <string name="bot_warning">
+Stai parlando con un bot, [NAME]. Non condividere informazioni personali.
+Scopri di più su https://second.life/scripted-agents.
+ </string>
<string name="facebook_post_success">Hai pubblicato su Facebook.</string>
<string name="flickr_post_success">Hai pubblicato su Flickr.</string>
<string name="twitter_post_success">Hai pubblicato su Twitter.</string>
diff --git a/indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml
index f8837c40a7..844a556af1 100644
--- a/indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml
+++ b/indra/newview/skins/default/xui/ja/panel_settings_sky_sunmoon.xml
@@ -44,8 +44,6 @@
<check_box label="ビーコンを表示" name="sunbeacon"/>
</layout_panel>
<layout_panel name="moon_layout">
- <layout_stack name="moon_stack">
- <layout_panel name="moon_layout">
<text name="moon_label">
月
</text>
@@ -74,8 +72,6 @@
</text>
<slider name="moon_brightness"/>
<check_box label="ビーコンを表示" name="moonbeacon"/>
- </layout_panel>
- </layout_stack>
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml
index c55c11e928..04ecba4264 100644
--- a/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/ja/panel_snapshot_inventory.xml
@@ -6,7 +6,7 @@
</text>
<view_border name="hr"/>
<combo_box label="解åƒåº¦" name="texture_size_combo">
- <combo_box.item label="ç¾åœ¨ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ (512✕512)" name="CurrentWindow"/>
+ <combo_box.item label="ç¾åœ¨ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦" name="CurrentWindow"/>
<combo_box.item label="å°ï¼ˆ128✕128)" name="Small(128x128)"/>
<combo_box.item label="中(256✕256)" name="Medium(256x256)"/>
<combo_box.item label="大(512✕512)" name="Large(512x512)"/>
@@ -16,7 +16,7 @@
<spinner label="" name="inventory_snapshot_height"/>
<check_box label="縦横比ã®å›ºå®š" name="inventory_keep_aspect_check"/>
<text name="hint_lbl">
- ç”»åƒã‚’テクスãƒãƒ£ã¨ã—ã¦ä¿å­˜ã™ã‚‹å ´åˆã¯ã€ã„ãšã‚Œã‹ã®æ­£æ–¹å½¢ã‚’é¸æŠžã—ã¦ãã ã•ã„。
+ ç”»åƒã‚’インベントリã«ä¿å­˜ã™ã‚‹ã«ã¯ L$[UPLOAD_COST] ã®è²»ç”¨ãŒã‹ã‹ã‚Šã¾ã™ã€‚ç”»åƒã‚’テクスãƒãƒ£ã¨ã—ã¦ä¿å­˜ã™ã‚‹ã«ã¯å¹³æ–¹å½¢å¼ã® 1 ã¤ã‚’é¸æŠžã—ã¦ãã ã•ã„。
</text>
<button label="キャンセル" name="cancel_btn"/>
<button label="ä¿å­˜" name="save_btn"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
index 7a1aa280ec..a979e31c9a 100644
--- a/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/ja/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="ディスクã«ä¿å­˜" name="save_to_computer_btn"/>
- <button label="インベントリã«ä¿å­˜ï¼ˆL$ [AMOUNT])" name="save_to_inventory_btn"/>
+ <button label="インベントリã«ä¿å­˜" name="save_to_inventory_btn"/>
<button label="プロフィールフィードã§å…±æœ‰ã™ã‚‹" name="save_to_profile_btn"/>
<button label="メールã§é€ä¿¡" name="save_to_email_btn"/>
<text name="fee_hint_lbl">
diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml
index d04c514322..d0e3cd87c4 100644
--- a/indra/newview/skins/default/xui/ja/strings.xml
+++ b/indra/newview/skins/default/xui/ja/strings.xml
@@ -66,7 +66,6 @@ SLURL:&lt;nolink&gt;[SLURL]&lt;/nolink&gt;
帯域幅:[NET_BANDWITH]kbitï¼ç§’
LOD係数:[LOD_FACTOR]
æç”»ã®è³ªï¼š[RENDER_QUALITY]
-高度ãªå…‰æºãƒ¢ãƒ‡ãƒ«ï¼š[GPU_SHADERS]
テクスãƒãƒ£ãƒ¡ãƒ¢ãƒªï¼š[TEXTURE_MEMORY]㎆
</string>
<string name="AboutOSXHiDPI">
@@ -6150,6 +6149,10 @@ www.secondlife.com ã‹ã‚‰æœ€æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ダウンロードã—ã¦ãã ã
<string name="inventory_folder_offered-im">
フォルダ「[ITEM_NAME]ã€ãŒã‚¤ãƒ³ãƒ™ãƒ³ãƒˆãƒªã«é€ã‚‰ã‚Œã¦ãã¾ã—ãŸã€‚
</string>
+ <string name="bot_warning">
+[NAME]ã¨ãƒãƒ£ãƒƒãƒˆã—ã¦ã„ã¾ã™ã€‚個人情報を共有ã—ãªã„ã§ãã ã•ã„。
+詳細㯠https://second.life/scripted-agents ã‚’ã”覧ãã ã•ã„。
+ </string>
<string name="share_alert">
インベントリã‹ã‚‰ã“ã“ã«ã‚¢ã‚¤ãƒ†ãƒ ã‚’ドラッグã—ã¾ã™ã€‚
</string>
diff --git a/indra/newview/skins/default/xui/pl/panel_settings_sky_sunmoon.xml b/indra/newview/skins/default/xui/pl/panel_settings_sky_sunmoon.xml
index f807148617..7f9dee2369 100644
--- a/indra/newview/skins/default/xui/pl/panel_settings_sky_sunmoon.xml
+++ b/indra/newview/skins/default/xui/pl/panel_settings_sky_sunmoon.xml
@@ -35,8 +35,6 @@
<check_box label="Pokaż emiter" name="sunbeacon" />
</layout_panel>
<layout_panel name="moon_layout">
- <layout_stack name="moon_stack">
- <layout_panel name="moon_layout">
<text name="moon_label">
Księżyc
</text>
@@ -59,8 +57,6 @@
Jasność:
</text>
<check_box label="Pokaż emiter" name="moonbeacon" />
- </layout_panel>
- </layout_stack>
</layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml b/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml
index 016b9ca197..04c01940e1 100644
--- a/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/pl/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel name="panel_snapshot_options">
<button label="Zapisz na dysku twardym" name="save_to_computer_btn" />
- <button label="Zapisz do Szafy ([AMOUNT]L$)" name="save_to_inventory_btn" />
+ <button label="Zapisz do Szafy" name="save_to_inventory_btn" />
<button label="Wyślij na mój Kanał" name="save_to_profile_btn" />
<button label="Załaduj na Facebook" name="send_to_facebook_btn" />
<button label="Załaduj na Twitter" name="send_to_twitter_btn" />
diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml
index 26ec6cc9dc..65b487e1b3 100644
--- a/indra/newview/skins/default/xui/pl/strings.xml
+++ b/indra/newview/skins/default/xui/pl/strings.xml
@@ -49,7 +49,6 @@ Pole widzenia (Draw Distance): [DRAW_DISTANCE]m
Przepustowość (Bandwidth): [NET_BANDWITH]kbit/s
Mnożnik poziomu detali (LOD Factor): [LOD_FACTOR]
Jakość wyświetlania (Render quality): [RENDER_QUALITY]
-Zaawansowane oświetlenie (Advanced Lighting Model): [GPU_SHADERS]
Pamięć tekstur (Texture memory): [TEXTURE_MEMORY]MB
Pamięć podręczna dysku (Disk cache): [DISK_CACHE_INFO]
</string>
@@ -4413,6 +4412,10 @@ Jeżeli nadal otrzymujesz ten komunikat, skontaktuj się z [SUPPORT_SITE].
<string name="inventory_folder_offered-im">
Zaoferowano folder: '[ITEM_NAME]'
</string>
+ <string name="bot_warning">
+Rozmawiasz z botem [NAME]. Nie udostępniaj żadnych danych osobowych.
+Dowiedz się więcej na https://second.life/scripted-agents.
+ </string>
<string name="share_alert">
PrzeciÄ…gaj tutaj rzeczy z Szafy
</string>
diff --git a/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml
index f3357026d5..28a5142baa 100644
--- a/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/pt/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
Salvar uma imagem em seu inventário custa L$[UPLOAD_COST]. Para salvar sua imagem como uma textura, selecione um dos formatos quadrados.
</text>
<combo_box label="Resolução" name="texture_size_combo">
- <combo_box.item label="Janela ativa (512x512)" name="CurrentWindow"/>
+ <combo_box.item label="Janela ativa" name="CurrentWindow"/>
<combo_box.item label="Pequeno (128x128)" name="Small(128x128)"/>
<combo_box.item label="Médio (256x256)" name="Medium(256x256)"/>
<combo_box.item label="Grande (512x512)" name="Large(512x512)"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml b/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml
index 067e5dbd76..f71bc7cd12 100644
--- a/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/pt/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="Salvar no disco" name="save_to_computer_btn"/>
- <button label="Salvar em inventário (L$[AMOUNT])" name="save_to_inventory_btn"/>
+ <button label="Salvar em inventário" name="save_to_inventory_btn"/>
<button label="Compartilhar no feed do perfil" name="save_to_profile_btn"/>
<button label="Compartilhar no Facebook" name="send_to_facebook_btn"/>
<button label="Compartilhar no Twitter" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index 0b12dd2aa0..c7fe195505 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -29,7 +29,6 @@ Estabelecer a distância: [DRAW_DISTANCE]m
Largura da banda: [NET_BANDWITH]kbit/s
LOD fator: [LOD_FACTOR]
Qualidade de renderização: [RENDER_QUALITY]
-Modelo avançado de luzes: [GPU_SHADERS]
Memória de textura: [TEXTURE_MEMORY]MB</string>
<string name="AboutOSXHiDPI">HiDPI modo de exibição: [HIDPI]</string>
<string name="AboutLibs">Versão do J2C Decoder: [J2C_VERSION]
@@ -1550,6 +1549,10 @@ If you continue to receive this message, contact the [SUPPORT_SITE].</string>
<string name="conference-title-incoming">Conversa com [AGENT_NAME]</string>
<string name="inventory_item_offered-im">Item do inventário '[ITEM_NAME]' oferecido</string>
<string name="inventory_folder_offered-im">Pasta do inventário '[ITEM_NAME]' oferecida</string>
+ <string name="bot_warning">
+Você está conversando com um bot, [NAME]. Não compartilhe informações pessoais.
+Saiba mais em https://second.life/scripted-agents.
+ </string>
<string name="facebook_post_success">Você publicou no Facebook.</string>
<string name="flickr_post_success">Você publicou no Flickr.</string>
<string name="twitter_post_success">Você publicou no Twitter.</string>
diff --git a/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml
index f07e12e0ed..adc612dfd8 100644
--- a/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/ru/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
Сохранение Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² инвентаре Ñтоит L$[UPLOAD_COST]. Чтобы Ñохранить его как текÑтуру, выберите один из квадратных форматов.
</text>
<combo_box label="Размер" name="texture_size_combo">
- <combo_box.item label="Текущее окно (512x512)" name="CurrentWindow"/>
+ <combo_box.item label="Текущее окно" name="CurrentWindow"/>
<combo_box.item label="Маленький (128x128)" name="Small(128x128)"/>
<combo_box.item label="Средний (256x256)" name="Medium(256x256)"/>
<combo_box.item label="Большой (512x512)" name="Large(512x512)"/>
diff --git a/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml b/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml
index 7ba03ee0c9..f7fda0b1dc 100644
--- a/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/ru/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="Сохранить на диÑке" name="save_to_computer_btn"/>
- <button label="Сохранить в инвентаре (L$[AMOUNT])" name="save_to_inventory_btn"/>
+ <button label="Сохранить в инвентаре" name="save_to_inventory_btn"/>
<button label="ПоделитьÑÑ Ð² профиле" name="save_to_profile_btn"/>
<button label="ПоделитьÑÑ Ð² Facebook" name="send_to_facebook_btn"/>
<button label="ПоделитьÑÑ Ð² Twitter" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml
index 649d5e7107..1f53723e92 100644
--- a/indra/newview/skins/default/xui/ru/strings.xml
+++ b/indra/newview/skins/default/xui/ru/strings.xml
@@ -69,7 +69,6 @@ SLURL: &lt;nolink&gt;[SLURL]&lt;/nolink&gt;
Ширина канала: [NET_BANDWITH] кбит/Ñ
КоÑффициент детализации: [LOD_FACTOR]
КачеÑтво визуализации: [RENDER_QUALITY]
-РаÑÑˆÐ¸Ñ€ÐµÐ½Ð½Ð°Ñ Ð¼Ð¾Ð´ÐµÐ»ÑŒ оÑвещениÑ: [GPU_SHADERS]
ПамÑÑ‚ÑŒ текÑтур: [TEXTURE_MEMORY] МБ
</string>
<string name="AboutOSXHiDPI">
@@ -4577,6 +4576,10 @@ support@secondlife.com.
<string name="inventory_folder_offered-im">
Предложена папка Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Â«[ITEM_NAME]»
</string>
+ <string name="bot_warning">
+Ð’Ñ‹ общаетеÑÑŒ Ñ Ð±Ð¾Ñ‚Ð¾Ð¼ [NAME]. Ðе передавайте личные данные.
+Подробнее на https://second.life/scripted-agents.
+ </string>
<string name="share_alert">
ПеретаÑкивайте вещи из Ð¸Ð½Ð²ÐµÐ½Ñ‚Ð°Ñ€Ñ Ñюда
</string>
diff --git a/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml
index be5940c4b9..160cba8700 100644
--- a/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/tr/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
Bir görüntüyü envanterinize kaydetmenin maliyeti L$[UPLOAD_COST] olur. Görüntünüzü bir doku olarak kaydetmek için kare formatlardan birini seçin.
</text>
<combo_box label="Çözünürlük" name="texture_size_combo">
- <combo_box.item label="Mevcut Pencere(512x512)" name="CurrentWindow"/>
+ <combo_box.item label="Mevcut Pencere" name="CurrentWindow"/>
<combo_box.item label="Küçük (128x128)" name="Small(128x128)"/>
<combo_box.item label="Orta (256x256)" name="Medium(256x256)"/>
<combo_box.item label="Büyük (512x512)" name="Large(512x512)"/>
diff --git a/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml b/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml
index 1b48bbeec2..a028710b98 100644
--- a/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/tr/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="Diske Kaydet" name="save_to_computer_btn"/>
- <button label="Envantere Kaydet (L$[AMOUNT])" name="save_to_inventory_btn"/>
+ <button label="Envantere Kaydet" name="save_to_inventory_btn"/>
<button label="Profil Akışında Paylaş" name="save_to_profile_btn"/>
<button label="Facebook&apos;ta PaylaÅŸ" name="send_to_facebook_btn"/>
<button label="Twitter&apos;da PaylaÅŸ" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml
index f80d8e3382..c98de5aab9 100644
--- a/indra/newview/skins/default/xui/tr/strings.xml
+++ b/indra/newview/skins/default/xui/tr/strings.xml
@@ -69,7 +69,6 @@ UI Ölçeklendirme: [UI_SCALE]
Bant geniÅŸliÄŸi: [NET_BANDWITH]kbit/s
LOD faktörü: [LOD_FACTOR]
Ä°ÅŸleme kalitesi: [RENDER_QUALITY]
-Gelişmiş Aydınlatma Modeli: [GPU_SHADERS]
Doku belleÄŸi: [TEXTURE_MEMORY]MB
</string>
<string name="AboutOSXHiDPI">
@@ -4580,6 +4579,10 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne başvurun.
<string name="inventory_folder_offered-im">
&quot;[ITEM_NAME]&quot; envanter klasörü sunuldu
</string>
+ <string name="bot_warning">
+Bir bot ile sohbet ediyorsunuz, [NAME]. Kişisel bilgilerinizi paylaşmayın.
+Daha fazla bilgi için: https://second.life/scripted-agents.
+ </string>
<string name="share_alert">
Envanterinizden buraya öğeler sürükleyin
</string>
diff --git a/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml b/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml
index 094bf019b4..9c45c54a5e 100644
--- a/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml
+++ b/indra/newview/skins/default/xui/zh/panel_snapshot_inventory.xml
@@ -7,7 +7,7 @@
將圖åƒå„²å­˜åˆ°æ”¶ç´å€çš„費用為 L$[UPLOAD_COST]。 è‹¥è¦å°‡åœ–åƒå­˜ç‚ºæ質,請é¸æ“‡ä¸€å€‹æ­£æ–¹æ ¼å¼ã€‚
</text>
<combo_box label="解æžåº¦" name="texture_size_combo">
- <combo_box.item label="ç›®å‰è¦–窗(512x512)" name="CurrentWindow"/>
+ <combo_box.item label="ç›®å‰è¦–窗" name="CurrentWindow"/>
<combo_box.item label="å°ï¼ˆ128x128)" name="Small(128x128)"/>
<combo_box.item label="中(256x256)" name="Medium(256x256)"/>
<combo_box.item label="大(512x512)" name="Large(512x512)"/>
diff --git a/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml b/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml
index d7c65bb25e..d9536882ac 100644
--- a/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml
+++ b/indra/newview/skins/default/xui/zh/panel_snapshot_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel name="panel_snapshot_options">
<button label="儲存到硬碟" name="save_to_computer_btn"/>
- <button label="儲存到收ç´å€ï¼ˆL$[AMOUNT])" name="save_to_inventory_btn"/>
+ <button label="儲存到收ç´å€" name="save_to_inventory_btn"/>
<button label="分享至檔案訊æ¯ç™¼ä½ˆ" name="save_to_profile_btn"/>
<button label="分享到臉書" name="send_to_facebook_btn"/>
<button label="分享到推特" name="send_to_twitter_btn"/>
diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml
index bdb16c9bf1..59ba2a7e19 100644
--- a/indra/newview/skins/default/xui/zh/strings.xml
+++ b/indra/newview/skins/default/xui/zh/strings.xml
@@ -69,7 +69,6 @@
頻寬:[NET_BANDWITH]åƒä½å…ƒ/秒
細節層次率:[LOD_FACTOR]
呈åƒå“質:[RENDER_QUALITY]
-進階照明模型:[GPU_SHADERS]
æ質記憶體:[TEXTURE_MEMORY]MB
</string>
<string name="AboutOSXHiDPI">
@@ -4573,6 +4572,10 @@ http://secondlife.com/support 求助解決å•é¡Œã€‚
<string name="inventory_folder_offered-im">
收ç´å€è³‡æ–™å¤¾&apos;[ITEM_NAME]&apos;å·²å‘人æä¾›
</string>
+ <string name="bot_warning">
+您正在与人工智能机器人 [NAME] èŠå¤©ã€‚请勿分享任何个人信æ¯ã€‚
+了解更多:https://second.life/scripted-agents。
+ </string>
<string name="share_alert">
將收ç´å€ç‰©å“拖曳到這裡
</string>
diff --git a/indra/newview/tests/cppfeatures_test.cpp b/indra/newview/tests/cppfeatures_test.cpp
index f5ea3a522b..ca94dcfc95 100644
--- a/indra/newview/tests/cppfeatures_test.cpp
+++ b/indra/newview/tests/cppfeatures_test.cpp
@@ -283,7 +283,7 @@ void cpp_features_test_object_t::test<8>()
ensure("init member inline 1", ii.mFoo==10);
InitInlineWithConstructor iici;
- ensure("init member inline 2", iici.mFoo=10);
+ ensure("init member inline 2", iici.mFoo==10);
ensure("init member inline 3", iici.mBar==25);
}
diff --git a/indra/newview/tests/llgamecontrol_stub.cpp b/indra/newview/tests/llgamecontrol_stub.cpp
new file mode 100644
index 0000000000..b06a7fd132
--- /dev/null
+++ b/indra/newview/tests/llgamecontrol_stub.cpp
@@ -0,0 +1,99 @@
+/**
+ * @file llgamecontrol_stub.h
+ * @brief Stubbery for LLGameControl
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "llgamecontrol.h"
+
+#include "SDL2/SDL_events.h"
+
+LLGameControl::State g_state;
+
+// static
+bool LLGameControl::isInitialized()
+{
+ return false;
+}
+
+// static
+void LLGameControl::init()
+{
+}
+
+// static
+void LLGameControl::terminate()
+{
+}
+
+// static
+bool LLGameControl::computeFinalStateAndCheckForChanges()
+{
+ return false;
+}
+
+// static
+void LLGameControl::clearAllState()
+{
+}
+
+// static
+void LLGameControl::processEvents(bool app_has_focus)
+{
+}
+
+// static
+const LLGameControl::State& LLGameControl::getState()
+{
+ return g_state;
+}
+
+// static
+void LLGameControl::setIncludeKeyboard(bool include)
+{
+}
+
+// static
+bool LLGameControl::getIncludeKeyboard()
+{
+ return false;
+}
+
+// static
+LLGameControl::InputChannel LLGameControl::getChannelByActionName(const std::string& name)
+{
+ return LLGameControl::InputChannel();
+}
+
+// static
+void LLGameControl::addActionMapping(const std::string& name, LLGameControl::InputChannel channel)
+{
+}
+
+// static
+void LLGameControl::setActionFlags(U32 action_flags)
+{
+}
+
diff --git a/indra/newview/tests/llluamanager_test.cpp b/indra/newview/tests/llluamanager_test.cpp
new file mode 100644
index 0000000000..9687b68451
--- /dev/null
+++ b/indra/newview/tests/llluamanager_test.cpp
@@ -0,0 +1,523 @@
+/**
+ * @file llluamanager_test.cpp
+ * @author Nat Goodspeed
+ * @date 2023-09-28
+ * @brief Test for llluamanager.
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Copyright (c) 2023, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+//#include "llviewerprecompiledheaders.h"
+// associated header
+#include "../newview/llluamanager.h"
+// STL headers
+// std headers
+#include <vector>
+// external library headers
+// other Linden headers
+#include "../llcommon/tests/StringVec.h"
+#include "../test/lltut.h"
+#include "llapp.h"
+#include "llcontrol.h"
+#include "lldate.h"
+#include "llevents.h"
+#include "lleventcoro.h"
+#include "llsdutil.h"
+#include "lluri.h"
+#include "lluuid.h"
+#include "lua_function.h"
+#include "lualistener.h"
+#include "stringize.h"
+
+class LLTestApp : public LLApp
+{
+public:
+ bool init() override { return true; }
+ bool cleanup() override { return true; }
+ bool frame() override { return true; }
+};
+
+LLControlGroup gSavedSettings("Global");
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct llluamanager_data
+ {
+ llluamanager_data()
+ {
+ // Load gSavedSettings from source tree
+ // indra/newview/tests/llluamanager_test.cpp =>
+ // indra/newview
+ auto newview{ fsyspath(__FILE__).parent_path().parent_path() };
+ fsyspath settings{ newview / "app_settings" / "settings.xml" };
+ // true suppresses implicit declare; implicit declare requires
+ // that every variable in settings.xml has a Comment, which many don't.
+ gSavedSettings.loadFromFile(settings, true);
+ // At test time, since we don't have the app bundle available,
+ // extend LuaRequirePath to include the require directory in the
+ // source tree.
+ std::string require{ fsyspath(newview / "scripts" / "lua" / "require") };
+ auto paths{ gSavedSettings.getLLSD("LuaRequirePath") };
+ bool found = false;
+ for (const auto& path : llsd::inArray(paths))
+ {
+ if (path.asString() == require)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (! found)
+ {
+ paths.append(require);
+ gSavedSettings.setLLSD("LuaRequirePath", paths);
+ }
+ }
+ // We need an LLApp instance because LLLUAmanager uses coroutines,
+ // which suspend, and when a coroutine suspends it checks LLApp state,
+ // and if it's not APP_STATUS_RUNNING the coroutine terminates.
+ LLTestApp mApp;
+ };
+ typedef test_group<llluamanager_data> llluamanager_group;
+ typedef llluamanager_group::object object;
+ llluamanager_group llluamanagergrp("llluamanager");
+
+ static struct LuaExpr
+ {
+ std::string desc, expr;
+ LLSD expect;
+ } lua_expressions[] = {
+ { "nil", "nil", LLSD() },
+ { "true", "true", true },
+ { "false", "false", false },
+ { "int", "17", 17 },
+ { "real", "3.14", 3.14 },
+ { "string", "'string'", "string" },
+ // can't synthesize Lua userdata in Lua code: that can only be
+ // constructed by a C function
+ { "empty table", "{}", LLSD() },
+ { "nested empty table", "{ 1, 2, 3, {}, 5 }",
+ llsd::array(1, 2, 3, LLSD(), 5) },
+ { "nested non-empty table", "{ 1, 2, 3, {a=0, b=1}, 5 }",
+ llsd::array(1, 2, 3, llsd::map("a", 0, "b", 1), 5) },
+ };
+
+ template<> template<>
+ void object::test<1>()
+ {
+ set_test_name("test Lua results");
+ for (auto& luax : lua_expressions)
+ {
+ auto [count, result] =
+ LLLUAmanager::waitScriptLine("return " + luax.expr);
+ auto desc{ stringize("waitScriptLine(", luax.desc, "): ") };
+ // if count < 0, report Lua error message
+ ensure_equals(desc + result.asString(), count, 1);
+ ensure_equals(desc + "result", result, luax.expect);
+ }
+ }
+
+ void from_lua(const std::string& desc, std::string_view construct, const LLSD& expect)
+ {
+ LLSD fromlua;
+ LLStreamListener pump("testpump",
+ [&fromlua](const LLSD& data){ fromlua = data; });
+ const std::string lua(stringize(
+ "data = ", construct, "\n"
+ "LL.post_on('testpump', data)\n"
+ ));
+ auto [count, result] = LLLUAmanager::waitScriptLine(lua);
+ // We woke up again ourselves because the coroutine running Lua has
+ // finished. But our Lua chunk didn't actually return anything, so we
+ // expect count to be 0 and result to be undefined.
+ ensure_equals(desc + ": " + result.asString(), count, 0);
+ ensure_equals(desc, fromlua, expect);
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ set_test_name("LLSD from post_on()");
+ for (auto& luax : lua_expressions)
+ {
+ from_lua(luax.desc, luax.expr, luax.expect);
+ }
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ set_test_name("test post_on(), get_event_pumps(), get_event_next()");
+ StringVec posts;
+ LLStreamListener pump("testpump",
+ [&posts](const LLSD& data)
+ { posts.push_back(data.asString()); });
+ const std::string lua(
+ "-- test post_on,get_event_pumps,get_event_next\n"
+ "LL.post_on('testpump', 'entry')\n"
+ "LL.post_on('testpump', 'get_event_pumps()')\n"
+ "replypump, cmdpump = LL.get_event_pumps()\n"
+ "LL.post_on('testpump', replypump)\n"
+ "LL.post_on('testpump', 'get_event_next()')\n"
+ "pump, data = LL.get_event_next()\n"
+ "LL.post_on('testpump', data)\n"
+ "LL.post_on('testpump', 'exit')\n"
+ );
+ // It's important to let the startScriptLine() coroutine run
+ // concurrently with ours until we've had a chance to post() our
+ // reply.
+ auto future = LLLUAmanager::startScriptLine(lua);
+ StringVec expected{
+ "entry",
+ "get_event_pumps()",
+ "",
+ "get_event_next()",
+ "message",
+ "exit"
+ };
+ expected[2] = posts.at(2);
+ LL_DEBUGS() << "Found pumpname '" << expected[2] << "'" << LL_ENDL;
+ LLEventPump& luapump{ LLEventPumps::instance().obtain(expected[2]) };
+ LL_DEBUGS() << "Found pump '" << luapump.getName() << "', type '"
+ << LLError::Log::classname(luapump)
+ << "': post('" << expected[4] << "')" << LL_ENDL;
+ luapump.post(expected[4]);
+ auto [count, result] = future.get();
+ ensure_equals("post_on(): " + result.asString(), count, 0);
+ ensure_equals("post_on() sequence", posts, expected);
+ }
+
+ void round_trip(const std::string& desc, const LLSD& send, const LLSD& expect)
+ {
+ LLEventMailDrop testpump("testpump");
+ const std::string lua(
+ "-- test LLSD round trip\n"
+ "replypump, cmdpump = LL.get_event_pumps()\n"
+ "LL.post_on('testpump', replypump)\n"
+ "pump, data = LL.get_event_next()\n"
+ "return data\n"
+ );
+ auto future = LLLUAmanager::startScriptLine(lua);
+ // We woke up again ourselves because the coroutine running Lua has
+ // reached the get_event_next() call, which suspends the calling C++
+ // coroutine (including the Lua code running on it) until we post
+ // something to that reply pump.
+ auto luapump{ llcoro::suspendUntilEventOn(testpump).asString() };
+ LLEventPumps::instance().post(luapump, send);
+ // The C++ coroutine running the Lua script is now ready to run. Run
+ // it so it will echo the LLSD back to us.
+ auto [count, result] = future.get();
+ ensure_equals(stringize("round_trip(", desc, "): ", result.asString()), count, 1);
+ ensure_equals(desc, result, expect);
+ }
+
+ // Define an RTItem to be used for round-trip LLSD testing: what it is,
+ // what we send to Lua, what we expect to get back. They could be the
+ // same.
+ struct RTItem
+ {
+ RTItem(const std::string& name, const LLSD& send, const LLSD& expect):
+ mName(name),
+ mSend(send),
+ mExpect(expect)
+ {}
+ RTItem(const std::string& name, const LLSD& both):
+ mName(name),
+ mSend(both),
+ mExpect(both)
+ {}
+
+ std::string mName;
+ LLSD mSend, mExpect;
+ };
+
+ template<> template<>
+ void object::test<4>()
+ {
+ set_test_name("LLSD round trip");
+ LLSD::Binary binary{ 3, 1, 4, 1, 5, 9, 2, 6, 5 };
+ const char* uuid{ "01234567-abcd-0123-4567-0123456789ab" };
+ const char* date{ "2023-10-04T21:06:00Z" };
+ const char* uri{ "https://secondlife.com/index.html" };
+ std::vector<RTItem> items{
+ RTItem("undefined", LLSD()),
+ RTItem("true", true),
+ RTItem("false", false),
+ RTItem("int", 17),
+ RTItem("real", 3.14),
+ RTItem("int real", 27.0, 27),
+ RTItem("string", "string"),
+ RTItem("binary", binary),
+ RTItem("empty array", LLSD::emptyArray(), LLSD()),
+ RTItem("empty map", LLSD::emptyMap(), LLSD()),
+ RTItem("UUID", LLUUID(uuid), uuid),
+ RTItem("date", LLDate(date), date),
+ RTItem("uri", LLURI(uri), uri)
+ };
+ // scalars
+ for (const auto& item: items)
+ {
+ round_trip(item.mName, item.mSend, item.mExpect);
+ }
+
+ // array
+ LLSD send_array{ LLSD::emptyArray() }, expect_array{ LLSD::emptyArray() };
+ for (const auto& item: items)
+ {
+ send_array.append(item.mSend);
+ expect_array.append(item.mExpect);
+ }
+ // exercise the array tail trimming below
+ send_array.append(items[0].mSend);
+ expect_array.append(items[0].mExpect);
+ // Lua takes a table value of nil to mean: don't store this key. An
+ // LLSD array containing undefined entries (converted to nil) leaves
+ // "holes" in the Lua table. These will be converted back to undefined
+ // LLSD entries -- except at the end. Trailing undefined entries are
+ // simply omitted from the table -- so the table converts back to a
+ // shorter LLSD array. We've constructed send_array and expect_array
+ // according to 'items' above -- but truncate from expect_array any
+ // trailing entries whose mSend will map to Lua nil.
+ while (expect_array.size() > 0 &&
+ send_array[expect_array.size() - 1].isUndefined())
+ {
+ expect_array.erase(LLSD::Integer(expect_array.size() - 1));
+ }
+ round_trip("array", send_array, expect_array);
+
+ // map
+ LLSD send_map{ LLSD::emptyMap() }, expect_map{ LLSD::emptyMap() };
+ for (const auto& item: items)
+ {
+ send_map[item.mName] = item.mSend;
+ // see comment in the expect_array truncation loop above --
+ // Lua never stores table entries with nil values
+ if (item.mSend.isDefined())
+ {
+ expect_map[item.mName] = item.mExpect;
+ }
+ }
+ round_trip("map", send_map, expect_map);
+
+ // deeply nested map: exceed Lua's default stack space (20),
+ // i.e. verify that we have the right checkstack() calls
+ for (int i = 0; i < 20; ++i)
+ {
+ LLSD new_send_map{ send_map }, new_expect_map{ expect_map };
+ new_send_map["nested map"] = send_map;
+ new_expect_map["nested map"] = expect_map;
+ send_map = new_send_map;
+ expect_map = new_expect_map;
+ }
+ round_trip("nested map", send_map, expect_map);
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ set_test_name("leap.request() from main thread");
+ const std::string lua(
+ "-- leap.request() from main thread\n"
+ "\n"
+ "leap = require 'leap'\n"
+ "\n"
+ "return {\n"
+ " a=leap.request('echo', {data='a'}).data,\n"
+ " b=leap.request('echo', {data='b'}).data\n"
+ "}\n"
+ );
+
+ LLStreamListener pump(
+ "echo",
+ [](const LLSD& data)
+ {
+ LL_DEBUGS("Lua") << "echo pump got: " << data << LL_ENDL;
+ sendReply(data, data);
+ });
+
+ auto [count, result] = LLLUAmanager::waitScriptLine(lua);
+ ensure_equals("Lua script didn't return item", count, 1);
+ ensure_equals("echo failed", result, llsd::map("a", "a", "b", "b"));
+ }
+
+ template<> template<>
+ void object::test<6>()
+ {
+ set_test_name("interleave leap.request() responses");
+ const std::string lua(
+ "-- interleave leap.request() responses\n"
+ "\n"
+ "fiber = require('fiber')\n"
+ "leap = require('leap')\n"
+ "local function debug(...) end\n"
+ "-- debug = require('printf')\n"
+ "\n"
+ "-- negative priority ensures catchall is always last\n"
+ "catchall = leap.WaitFor(-1, 'catchall')\n"
+ "function catchall:filter(pump, data)\n"
+ " debug('catchall:filter(%s, %s)', pump, data)\n"
+ " return data\n"
+ "end\n"
+ "\n"
+ "-- but first, catch events with 'special' key\n"
+ "catch_special = leap.WaitFor(2, 'catch_special')\n"
+ "function catch_special:filter(pump, data)\n"
+ " debug('catch_special:filter(%s, %s)', pump, data)\n"
+ " return if data['special'] ~= nil then data else nil\n"
+ "end\n"
+ "\n"
+ "function drain(waitfor)\n"
+ " debug('%s start', waitfor.name)\n"
+ " -- It seems as though we ought to be able to code this loop\n"
+ " -- over waitfor:wait() as:\n"
+ " -- for item in waitfor.wait, waitfor do\n"
+ " -- However, that seems to stitch a detour through C code into\n"
+ " -- the coroutine call stack, which prohibits coroutine.yield():\n"
+ " -- 'attempt to yield across metamethod/C-call boundary'\n"
+ " -- So we resort to two different calls to waitfor:wait().\n"
+ " local item = waitfor:wait()\n"
+ " while item do\n"
+ " debug('%s caught %s', waitfor.name, item)\n"
+ " item = waitfor:wait()\n"
+ " end\n"
+ " debug('%s done', waitfor.name)\n"
+ "end\n"
+ "\n"
+ "function requester(name)\n"
+ " debug('requester(%s) start', name)\n"
+ " local response = leap.request('testpump', {name=name})\n"
+ " debug('requester(%s) got %s', name, response)\n"
+ " -- verify that the correct response was dispatched to this coroutine\n"
+ " assert(response.name == name)\n"
+ "end\n"
+ "\n"
+ "-- fiber.print_all()\n"
+ "fiber.launch('catchall', drain, catchall)\n"
+ "fiber.launch('catch_special', drain, catch_special)\n"
+ "fiber.launch('requester(a)', requester, 'a')\n"
+ "fiber.launch('requester(b)', requester, 'b')\n"
+ // A script can normally count on an implicit fiber.run() call
+ // because fiber.lua calls LL.atexit(fiber.run). But atexit()
+ // functions are called by ~LuaState(), which (in the code below)
+ // won't be called until *after* we expect to interact with the
+ // various fibers. So make an explicit call for test purposes.
+ "fiber.run()\n"
+ );
+
+ LLSD requests;
+ LLStreamListener pump(
+ "testpump",
+ [&requests](const LLSD& data)
+ {
+ LL_DEBUGS("Lua") << "testpump got: " << data << LL_ENDL;
+ requests.append(data);
+ });
+
+ auto future = LLLUAmanager::startScriptLine(lua);
+ // LuaState::expr() periodically interrupts a running chunk to ensure
+ // the rest of our coroutines get cycles. Nonetheless, for this test
+ // we have to wait until both requester() coroutines have posted and
+ // are waiting for a reply.
+ for (unsigned count=0; count < 100; ++count)
+ {
+ if (requests.size() == 2)
+ break;
+ llcoro::suspend();
+ }
+ ensure_equals("didn't get both requests", requests.size(), 2);
+ auto replyname{ requests[0]["reply"].asString() };
+ auto& replypump{ LLEventPumps::instance().obtain(replyname) };
+ // moreover, we expect they arrived in the order they were created
+ ensure_equals("a wasn't first", requests[0]["name"].asString(), "a");
+ ensure_equals("b wasn't second", requests[1]["name"].asString(), "b");
+ replypump.post(llsd::map("special", "K"));
+ // respond to requester(b) FIRST
+ replypump.post(requests[1]);
+ replypump.post(llsd::map("name", "not special"));
+ // now respond to requester(a)
+ replypump.post(requests[0]);
+ // tell leap we're done
+ replypump.post(LLSD());
+ auto [count, result] = future.get();
+ ensure_equals("leap.lua: " + result.asString(), count, 0);
+ }
+
+ template<> template<>
+ void object::test<7>()
+ {
+ set_test_name("stop hanging Lua script");
+ const std::string lua(
+ "-- hanging Lua script should terminate\n"
+ "\n"
+ "LL.get_event_next()\n"
+ );
+ auto future = LLLUAmanager::startScriptLine(lua);
+ // Poke LLTestApp to send its preliminary shutdown message.
+ mApp.setQuitting();
+ // but now we have to give the startScriptLine() coroutine a chance to run
+ auto [count, result] = future.get();
+ ensure_equals("killed Lua script terminated normally", count, -1);
+ ensure_contains("unexpected killed Lua script error",
+ result.asString(), "viewer is stopping");
+ }
+
+ template<> template<>
+ void object::test<8>()
+ {
+ set_test_name("stop looping Lua script");
+ const std::string desc("looping Lua script should terminate");
+ const std::string lua(
+ "-- " + desc + "\n"
+ "\n"
+ "while true do\n"
+ " x = 1\n"
+ "end\n"
+ );
+ auto [count, result] = LLLUAmanager::waitScriptLine(lua);
+ // We expect the above erroneous script has been forcibly terminated
+ // because it ran too long without doing any actual work.
+ ensure_equals(desc + " count: " + result.asString(), count, -1);
+ ensure_contains(desc + " result", result.asString(), "terminated");
+ }
+
+ template <typename T>
+ struct Visible
+ {
+ Visible(T name): name(name)
+ {
+ LL_INFOS() << "Visible<" << LLError::Log::classname<T>() << ">('" << name << "')" << LL_ENDL;
+ }
+ Visible(const Visible&) = delete;
+ Visible& operator=(const Visible&) = delete;
+ ~Visible()
+ {
+ LL_INFOS() << "~Visible<" << LLError::Log::classname<T>() << ">('" << name << "')" << LL_ENDL;
+ }
+ T name;
+ };
+
+ template<> template<>
+ void object::test<9>()
+ {
+ set_test_name("track distinct lua_emplace<T>() types");
+ LuaState L;
+ lua_emplace<Visible<std::string>>(L, "std::string 0");
+ int st0tag = lua_userdatatag(L, -1);
+ lua_emplace<Visible<const char*>>(L, "const char* 0");
+ int cp0tag = lua_userdatatag(L, -1);
+ lua_emplace<Visible<std::string>>(L, "std::string 1");
+ int st1tag = lua_userdatatag(L, -1);
+ lua_emplace<Visible<const char*>>(L, "const char* 1");
+ int cp1tag = lua_userdatatag(L, -1);
+ lua_settop(L, 0);
+ ensure_equals("lua_emplace<std::string>() tags diverge", st0tag, st1tag);
+ ensure_equals("lua_emplace<const char*>() tags diverge", cp0tag, cp1tag);
+ ensure_not_equals("lua_emplace<>() tags collide", st0tag, cp0tag);
+ }
+} // namespace tut
diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp
index 8049e67fc5..b07800cdcd 100644
--- a/indra/newview/tests/llversioninfo_test.cpp
+++ b/indra/newview/tests/llversioninfo_test.cpp
@@ -29,7 +29,10 @@
#include "../llversioninfo.h"
- #include <iostream>
+#include <iostream>
+
+//#include "llgamecontrol_stub.cpp"
+
// LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The
// macro expands to the string name of the channel, but without quotes. We
diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp
index 9ee6625bf1..9a7a5be09f 100644
--- a/indra/newview/tests/llviewerhelputil_test.cpp
+++ b/indra/newview/tests/llviewerhelputil_test.cpp
@@ -79,6 +79,8 @@ bool LLAgent::isGodlike() const { return false; }
LLAgent gAgent;
+LLFlycam::LLFlycam() { }
+
std::string LLWeb::expandURLSubstitutions(const std::string &url,
const LLSD &default_subs)
{
diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp
index d5bf189d82..99c98f63ed 100644
--- a/indra/newview/tests/llworldmap_test.cpp
+++ b/indra/newview/tests/llworldmap_test.cpp
@@ -28,6 +28,7 @@
// Dependencies
#include "linden_common.h"
#include "llapr.h"
+#include "llcontrol.h" // LLControlGroup
#include "llsingleton.h"
#include "lltrans.h"
#include "lluistring.h"
@@ -71,6 +72,8 @@ void LLUIString::updateResult() const { }
void LLUIString::setArg(const std::string& , const std::string& ) { }
void LLUIString::assign(const std::string& ) { }
+LLControlGroup gSavedSettings("Global"); // saved at end of session
+
// End Stubbing
// -------------------------------------------------------------------------------------------
@@ -131,6 +134,7 @@ namespace tut
// Constructor and destructor of the test wrapper
worldmap_test()
{
+ gSavedSettings.declareBOOL("Use24HourClock", true, "", LLControlVariable::PERSIST_NO);
mWorld = LLWorldMap::getInstance();
}
~worldmap_test()
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 8089abd7fd..18ff6cf7b6 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -72,6 +72,7 @@ class ViewerManifest(LLManifest):
self.exclude("logcontrol.xml")
self.exclude("logcontrol-dev.xml")
self.path("*.ini")
+ self.path("*.txt")
self.path("*.xml")
# include the entire shaders directory recursively
@@ -168,6 +169,8 @@ class ViewerManifest(LLManifest):
self.path("*/*/*/*.js")
self.path("*/*/*.html")
+ self.path('scripts/lua')
+
#build_data.json. Standard with exception handling is fine. If we can't open a new file for writing, we have worse problems
#platform is computed above with other arg parsing
build_data_dict = {"Type":"viewer","Version":'.'.join(self.args['version']),
@@ -277,13 +280,13 @@ class ViewerManifest(LLManifest):
# All lines up to and including the first blank line are the file header; skip them
lines.reverse() # so that pop will pull from first to last line
- while not re.match("\s*$", lines.pop()) :
+ while not re.match(r"\s*$", lines.pop()) :
pass # do nothing
# A line that starts with a non-whitespace character is a name; all others describe contributions, so collect the names
names = []
for line in lines :
- if re.match("\S", line) :
+ if re.match(r"\S", line) :
names.append(line.rstrip())
# It's not fair to always put the same people at the head of the list
random.shuffle(names)
@@ -582,6 +585,9 @@ class Windows_x86_64_Manifest(ViewerManifest):
self.path("vivoxsdk_x64.dll")
self.path("ortp_x64.dll")
+ # SDL2
+ self.path("SDL2.dll")
+
# BugSplat
if self.args.get('bugsplat'):
self.path("BsSndRpt64.exe")
@@ -926,6 +932,7 @@ class Darwin_x86_64_Manifest(ViewerManifest):
with self.prefix(src=relpkgdir, dst=""):
self.path("libndofdev.dylib")
+ self.path("libSDL2-*.dylib")
with self.prefix(src_dst="cursors_mac"):
self.path("*.tif")
@@ -1025,381 +1032,12 @@ class Darwin_x86_64_Manifest(ViewerManifest):
):
dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
- # our apps
- executable_path = {}
- embedded_apps = [ (os.path.join("llplugin", "slplugin"), "SLPlugin.app") ]
- for app_bld_dir, app in embedded_apps:
- self.path2basename(os.path.join(os.pardir,
- app_bld_dir, self.args['configuration']),
- app)
- executable_path[app] = \
- self.dst_path_of(os.path.join(app, "Contents", "MacOS"))
-
- # our apps dependencies on shared libs
- # for each app, for each dylib we collected in dylibs,
- # create a symlink to the real copy of the dylib.
- with self.prefix(dst=os.path.join(app, "Contents", "Resources")):
- for libfile in dylibs:
- self.relsymlinkf(os.path.join(libfile_parent, libfile))
-
- # Dullahan helper apps go inside SLPlugin.app
- with self.prefix(dst=os.path.join(
- "SLPlugin.app", "Contents", "Frameworks")):
-
- frameworkname = 'Chromium Embedded Framework'
-
- # This code constructs a relative symlink from the
- # target framework folder back to the real CEF framework.
- # It needs to be relative so that the symlink still works when
- # (as is normal) the user moves the app bundle out of the DMG
- # and into the /Applications folder. Note we pass catch=False,
- # letting the uncaught exception terminate the process, since
- # without this symlink, Second Life web media can't possibly work.
-
- # It might seem simpler just to symlink Frameworks back to
- # the parent of Chromimum Embedded Framework.framework. But
- # that would create a symlink cycle, which breaks our
- # packaging step. So make a symlink from Chromium Embedded
- # Framework.framework to the directory of the same name, which
- # is NOT an ancestor of the symlink.
-
- # from SLPlugin.app/Contents/Frameworks/Chromium Embedded
- # Framework.framework back to
- # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework
- SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False)
-
- # for all the multiple CEF/Dullahan (as of CEF 76) helper app bundles we need:
- for helper in (
- "DullahanHelper",
- "DullahanHelper (GPU)",
- "DullahanHelper (Renderer)",
- "DullahanHelper (Plugin)",
- ):
- # app is the directory name of the app bundle, with app/Contents/MacOS/helper as the executable
- app = helper + ".app"
-
- # copy DullahanHelper.app
- self.path2basename(relpkgdir, app)
-
- # and fix that up with a Frameworks/CEF symlink too
- with self.prefix(dst=os.path.join(
- app, 'Contents', 'Frameworks')):
- # from Dullahan Helper *.app/Contents/Frameworks/Chromium Embedded
- # Framework.framework back to
- # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework
- # Since SLPlugin_framework is itself a
- # symlink, don't let relsymlinkf() resolve --
- # explicitly call relpath(symlink=True) and
- # create that symlink here.
- helper_framework = \
- self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), catch=False)
-
- # change_command includes install_name_tool, the
- # -change subcommand and the old framework rpath
- # stamped into the executable. To use it with
- # run_command(), we must still append the new
- # framework path and the pathname of the
- # executable to change.
- change_command = [
- 'install_name_tool', '-change',
- '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework']
-
- with self.prefix(dst=os.path.join(
- app, 'Contents', 'MacOS')):
- # Now self.get_dst_prefix() is, at runtime,
- # @executable_path. Locate the helper app
- # framework (which is a symlink) from here.
- newpath = os.path.join(
- '@executable_path',
- self.relpath(helper_framework, symlink=True),
- frameworkname)
- # and restamp the Dullahan Helper executable itself
- self.run_command(
- change_command +
- [newpath, self.dst_path_of(helper)])
-
- # SLPlugin plugins
- with self.prefix(dst="llplugin"):
- dylibexecutable = 'media_plugin_cef.dylib'
- self.path2basename("../media_plugins/cef/" + self.args['configuration'],
- dylibexecutable)
-
- # Do this install_name_tool *after* media plugin is copied over.
- # Locate the framework lib executable -- relative to
- # SLPlugin.app/Contents/MacOS, which will be our
- # @executable_path at runtime!
- newpath = os.path.join(
- '@executable_path',
- self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"],
- symlink=True),
- frameworkname)
- # restamp media_plugin_cef.dylib
- self.run_command(
- change_command +
- [newpath, self.dst_path_of(dylibexecutable)])
-
- # copy LibVLC plugin itself
- dylibexecutable = 'media_plugin_libvlc.dylib'
- self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], dylibexecutable)
- # add @rpath for the correct LibVLC subfolder
- self.run_command(['install_name_tool', '-add_rpath', '@loader_path/lib', self.dst_path_of(dylibexecutable)])
-
- # copy LibVLC dynamic libraries
- with self.prefix(src=relpkgdir, dst="lib"):
- self.path( "libvlc*.dylib*" )
- # copy LibVLC plugins folder
- with self.prefix(src='plugins', dst=""):
- self.path( "*.dylib" )
- self.path( "plugins.dat" )
-
- def package_finish(self):
- imagename = self.installer_base_name()
- self.set_github_output('imagename', imagename)
- finalname = imagename + ".dmg"
- self.package_file = finalname
-
- RUNNER_TEMP = os.getenv('RUNNER_TEMP')
- # When running as a GitHub Action job, RUNNER_TEMP is the recommended
- # temp directory. If we're not running on GitHub, don't create this
- # temp directory or this tarball: we don't clean them up, trusting
- # that the runner is itself transient. On a dev machine, that would
- # result in temp-directory clutter.
- if RUNNER_TEMP:
- # Per GitHub's actions/upload-artifact documentation
- # https://github.com/actions/upload-artifact#maintaining-file-permissions-and-case-sensitive-files
- # we must package the app bundle with tar before posting as an
- # artifact. Posting individual files follows symlinks, which
- # causes problems, especially with frameworks: a framework's top
- # level must contain symlinks into its Versions/Current, which
- # must itself be a symlink to some specific Versions subdir.
- tarpath = os.path.join(RUNNER_TEMP, "viewer.tar.xz")
- print(f'Creating {tarpath} from {self.get_dst_prefix()}')
- with tarfile.open(tarpath, mode="w:xz") as tarball:
- # Store in the tarball as just 'Second Life Mumble.app'
- # instead of 'Users/someone/.../newview/Release/Second...'
- # It's at this point that we rename 'Second Life Release.app'
- # to 'Second Life Viewer.app'.
- tarball.add(self.get_dst_prefix(),
- arcname=self.app_name() + ".app")
- self.set_github_output_path('viewer_app', tarpath)
-
-
-class Darwin_arm64_Manifest(ViewerManifest):
- build_data_json_platform = 'mac'
- address_size = 64
-
- def finish_build_data_dict(self, build_data_dict):
- build_data_dict.update({'Bundle Id':self.args['bundleid']})
- return build_data_dict
-
- def is_packaging_viewer(self):
- # darwin requires full app bundle packaging even for debugging.
- return True
-
- def is_rearranging(self):
- # That said, some stuff should still only be performed once.
- # Are either of these actions in 'actions'? Is the set intersection
- # non-empty?
- return bool(set(["package", "unpacked"]).intersection(self.args['actions']))
-
- def construct(self):
- # copy over the build result (this is a no-op if run within the xcode
- # script)
- self.path(os.path.join(self.args['configuration'], self.channel() + ".app"), dst="")
-
- pkgdir = os.path.join(self.args['build'], os.pardir, 'packages')
- relpkgdir = os.path.join(pkgdir, "lib", "release")
- debpkgdir = os.path.join(pkgdir, "lib", "debug")
-
- with self.prefix(src="", dst="Contents"): # everything goes in Contents
- bugsplat_db = self.args.get('bugsplat')
- if bugsplat_db:
- # Inject BugsplatServerURL into Info.plist if provided.
- Info_plist = self.dst_path_of("Info.plist")
- with open(Info_plist, 'rb') as f:
- Info = plistlib.load(f)
- # https://www.bugsplat.com/docs/platforms/os-x#configuration
- Info["BugsplatServerURL"] = \
- "https://{}.bugsplat.com/".format(bugsplat_db)
- self.put_in_file(
- plistlib.dumps(Info),
- os.path.basename(Info_plist),
- "Info.plist")
-
- # CEF framework goes inside Contents/Frameworks.
- # Remember where we parked this car.
- with self.prefix(src="", dst="Frameworks"):
- CEF_framework = "Chromium Embedded Framework.framework"
- self.path2basename(relpkgdir, CEF_framework)
- CEF_framework = self.dst_path_of(CEF_framework)
-
- if self.args.get('bugsplat'):
- self.path2basename(relpkgdir, "BugsplatMac.framework")
-
- with self.prefix(dst="MacOS"):
- executable = self.dst_path_of(self.channel())
- if self.args.get('bugsplat'):
- # According to Apple Technical Note TN2206:
- # https://developer.apple.com/library/archive/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG207
- # "If an app uses @rpath or an absolute path to link to a
- # dynamic library outside of the app, the app will be
- # rejected by Gatekeeper. ... Neither the codesign nor the
- # spctl tool will show the error."
- # (Thanks, Apple. Maybe fix spctl to warn?)
- # The BugsplatMac framework embeds @rpath, which is
- # causing scary Gatekeeper popups at viewer start. Work
- # around this by changing the reference baked into our
- # viewer. The install_name_tool -change option needs the
- # previous value. Instead of guessing -- which might
- # silently be defeated by a BugSplat SDK update that
- # changes their baked-in @rpath -- ask for the path
- # stamped into the framework.
- # Let exception, if any, propagate -- if this doesn't
- # work, we need the build to noisily fail!
- oldpath = subprocess.check_output(
- ['objdump', '--macho', '--dylib-id', '--non-verbose',
- os.path.join(relpkgdir, "BugsplatMac.framework", "BugsplatMac")],
- text=True
- ).splitlines()[-1] # take the last line of output
- self.run_command(
- ['install_name_tool', '-change', oldpath,
- '@executable_path/../Frameworks/BugsplatMac.framework/BugsplatMac',
- executable])
-
- # NOTE: the -S argument to strip causes it to keep
- # enough info for annotated backtraces (i.e. function
- # names in the crash log). 'strip' with no arguments
- # yields a slightly smaller binary but makes crash
- # logs mostly useless. This may be desirable for the
- # final release. Or not.
- if ("package" in self.args['actions'] or
- "unpacked" in self.args['actions']):
- self.run_command(
- ['strip', '-S', executable])
-
- with self.prefix(dst="Resources"):
- # defer cross-platform file copies until we're in the
- # nested Resources directory
- super().construct()
-
- # need .icns file referenced by Info.plist
- with self.prefix(src=self.icon_path(), dst="") :
- self.path("secondlife.icns")
-
- # Copy in the updater script and helper modules
- self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater")
-
- with self.prefix(src="", dst=os.path.join("updater", "icons")):
- self.path2basename(self.icon_path(), "secondlife.ico")
- with self.prefix(src="vmp_icons", dst=""):
- self.path("*.png")
- self.path("*.gif")
-
- with self.prefix(src=relpkgdir, dst=""):
- self.path("libndofdev.dylib")
- self.path("libhunspell-*.dylib")
-
- with self.prefix(src_dst="cursors_mac"):
- self.path("*.tif")
-
- self.path("licenses-mac.txt", dst="licenses.txt")
- self.path("featuretable_mac.txt")
- self.path("cube.dae")
- self.path("SecondLife.nib")
-
- with self.prefix(src=pkgdir,dst=""):
- self.path("ca-bundle.crt")
-
- # Translations
- self.path("English.lproj/language.txt")
- self.replace_in(src="English.lproj/InfoPlist.strings",
- dst="English.lproj/InfoPlist.strings",
- searchdict={'%%VERSION%%':'.'.join(self.args['version'])}
- )
- self.path("German.lproj")
- self.path("Japanese.lproj")
- self.path("Korean.lproj")
- self.path("da.lproj")
- self.path("es.lproj")
- self.path("fr.lproj")
- self.path("hu.lproj")
- self.path("it.lproj")
- self.path("nl.lproj")
- self.path("pl.lproj")
- self.path("pt.lproj")
- self.path("ru.lproj")
- self.path("tr.lproj")
- self.path("uk.lproj")
- self.path("zh-Hans.lproj")
-
- def path_optional(src, dst):
- """
- For a number of our self.path() calls, not only do we want
- to deal with the absence of src, we also want to remember
- which were present. Return either an empty list (absent)
- or a list containing dst (present). Concatenate these
- return values to get a list of all libs that are present.
- """
- # This was simple before we started needing to pass
- # wildcards. Fortunately, self.path() ends up appending a
- # (source, dest) pair to self.file_list for every expanded
- # file processed. Remember its size before the call.
- oldlen = len(self.file_list)
- try:
- self.path(src, dst)
- # The dest appended to self.file_list has been prepended
- # with self.get_dst_prefix(). Strip it off again.
- added = [os.path.relpath(d, self.get_dst_prefix())
- for s, d in self.file_list[oldlen:]]
- except MissingError as err:
- print("Warning: "+err.msg, file=sys.stderr)
- added = []
- if not added:
- print("Skipping %s" % dst)
- return added
-
- # dylibs is a list of all the .dylib files we expect to need
- # in our bundled sub-apps. For each of these we'll create a
- # symlink from sub-app/Contents/Resources to the real .dylib.
- # Need to get the llcommon dll from any of the build directories as well.
- libfile_parent = self.get_dst_prefix()
- dylibs=[]
+ # SDL2
for libfile in (
- "libapr-1.0.dylib",
- "libaprutil-1.0.dylib",
- "libexpat.1.dylib",
- # libnghttp2.dylib is a symlink to
- # libnghttp2.major.dylib, which is a symlink to
- # libnghttp2.version.dylib. Get all of them.
- "libnghttp2.*dylib",
- "liburiparser.*dylib",
- ):
+ 'libSDL2-2.0.dylib',
+ ):
dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
- # SLVoice executable
- with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')):
- self.path("SLVoice")
-
- # Vivox libraries
- for libfile in (
- 'libortp.dylib',
- 'libvivoxsdk.dylib',
- ):
- self.path2basename(relpkgdir, libfile)
-
- # Fmod studio dylibs (vary based on configuration)
- if self.args['fmodstudio'] == 'ON':
- if self.args['buildtype'].lower() == 'debug':
- for libfile in (
- "libfmodL.dylib",
- ):
- dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
- else:
- for libfile in (
- "libfmod.dylib",
- ):
- dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
-
# our apps
executable_path = {}
embedded_apps = [ (os.path.join("llplugin", "slplugin"), "SLPlugin.app") ]
@@ -1606,11 +1244,13 @@ class LinuxManifest(ViewerManifest):
with self.prefix(dst="res-sdl") :
self.path("secondlife_256.BMP","ll_icon.BMP")
+ with self.prefix(src=os.path.join(self.args['build'], os.pardir, "llwebrtc" ), dst="lib"):
+ self.path("libllwebrtc.so")
+
# plugins
with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"):
self.path("gstreamer10/libmedia_plugin_gstreamer10.so", "libmedia_plugin_gstreamer.so")
-
with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins'), dst="bin/llplugin"):
self.path("cef/libmedia_plugin_cef.so", "libmedia_plugin_cef.so" )
with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="lib"):
@@ -1777,50 +1417,18 @@ class Linux_x86_64_Manifest(LinuxManifest):
pkgdir = self.args['package_dir']
relpkgdir = os.path.join(pkgdir, "lib", "release")
- debpkgdir = os.path.join(pkgdir, "lib", "debug")
+ #debpkgdir = os.path.join(pkgdir, "lib", "debug")
with self.prefix(src=relpkgdir, dst="lib"):
- self.path("libdb*.so")
- self.path("libuuid.so*")
- self.path("libSDL-1.2.so.*")
- self.path("libdirectfb-1.*.so.*")
- self.path("libfusion-1.*.so.*")
- self.path("libdirect-1.*.so.*")
- self.path("libopenjp2.so*")
- self.path("libdirectfb-1.4.so.5")
- self.path("libfusion-1.4.so.5")
- self.path("libdirect-1.4.so.5*")
+ self.path("libapr-1.so*")
+ self.path("libaprutil-1.so*")
+ self.path_optional("libSDL*.so.*")
+
+ self.path_optional("libjemalloc*.so")
+
self.path("libalut.so*")
self.path("libopenal.so*")
self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname
- # KLUDGE: As of 2012-04-11, the 'fontconfig' package installs
- # libfontconfig.so.1.4.4, along with symlinks libfontconfig.so.1
- # and libfontconfig.so. Before we added support for library-file
- # wildcards, though, this self.path() call specifically named
- # libfontconfig.so.1.4.4 WITHOUT also copying the symlinks. When I
- # (nat) changed the call to self.path("libfontconfig.so.*"), we
- # ended up with the libfontconfig.so.1 symlink in the target
- # directory as well. But guess what! At least on Ubuntu 10.04,
- # certain viewer fonts look terrible with libfontconfig.so.1
- # present in the target directory. Removing that symlink suffices
- # to improve them. I suspect that means we actually do better when
- # the viewer fails to find our packaged libfontconfig.so*, falling
- # back on the system one instead -- but diagnosing and fixing that
- # is a bit out of scope for the present project. Meanwhile, this
- # particular wildcard specification gets us exactly what the
- # previous call did, without having to explicitly state the
- # version number.
- self.path("libfontconfig.so.*.*")
-
- # Include libfreetype.so. but have it work as libfontconfig does.
- self.path("libfreetype.so.*.*")
-
- try:
- self.path("libtcmalloc.so*") #formerly called google perf tools
- pass
- except:
- print("tcmalloc files not found, skipping")
- pass
# Vivox runtimes
with self.prefix(src=relpkgdir, dst="bin"):