diff --git a/addons/common/fnc_createNamespace.sqf b/addons/common/fnc_createNamespace.sqf index 9c5ca7863..d169c1207 100644 --- a/addons/common/fnc_createNamespace.sqf +++ b/addons/common/fnc_createNamespace.sqf @@ -7,14 +7,17 @@ Description: The Namespace is destroyed after the mission ends. getVariable ARRAY is not supported. Parameters: - None + _isGlobal - create a global namespace (optional, default: false) Returns: - _namespace - a namespace + _namespace - a namespace Examples: (begin example) _namespace = call CBA_fnc_createNamespace; + + My_GlobalNamespace = true call CBA_fnc_createNamespace; + publicVariable "My_GlobalNamespace"; (end) Author: @@ -23,4 +26,10 @@ Author: #include "script_component.hpp" SCRIPT(createNamespace); -createLocation ["CBA_NamespaceDummy", [-1000, -1000, 0], 0, 0] +params [["_isGlobal", false]]; + +if (_isGlobal isEqualTo true) then { + createVehicle ["Building", [-1000, -1000, 0], [], 0, "NONE"] +} else { + createLocation ["CBA_NamespaceDummy", [-1000, -1000, 0], 0, 0] +}; diff --git a/addons/common/fnc_deleteNamespace.sqf b/addons/common/fnc_deleteNamespace.sqf index 8ed1d53b3..6308f8e25 100644 --- a/addons/common/fnc_deleteNamespace.sqf +++ b/addons/common/fnc_deleteNamespace.sqf @@ -21,6 +21,6 @@ Author: #include "script_component.hpp" SCRIPT(deleteNamespace); -params [["_namespace", locationNull, [locationNull]]]; +params [["_namespace", locationNull, [locationNull, objNull]]]; -deleteLocation _namespace; +_namespace call CBA_fnc_deleteEntity; diff --git a/addons/keybinding/CfgEventHandlers.hpp b/addons/keybinding/CfgEventHandlers.hpp index e4cc840f7..a5a470efd 100644 --- a/addons/keybinding/CfgEventHandlers.hpp +++ b/addons/keybinding/CfgEventHandlers.hpp @@ -1,8 +1,12 @@ -class Extended_PreInit_EventHandlers -{ - class ADDON - { - clientInit = QUOTE(call COMPILE_FILE(XEH_preClientInit)); + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); }; }; +class Extended_DisplayLoad_EventHandlers { + class RscDisplayConfigure { + ADDON = QUOTE(_this call COMPILE_FILE(XEH_configureDisplayLoad)); + }; +}; diff --git a/addons/keybinding/gui/initDisplay.sqf b/addons/keybinding/XEH_configureDisplayLoad.sqf similarity index 100% rename from addons/keybinding/gui/initDisplay.sqf rename to addons/keybinding/XEH_configureDisplayLoad.sqf diff --git a/addons/keybinding/XEH_preClientInit.sqf b/addons/keybinding/XEH_preInit.sqf similarity index 98% rename from addons/keybinding/XEH_preClientInit.sqf rename to addons/keybinding/XEH_preInit.sqf index f456d4d20..4cb0be2e4 100644 --- a/addons/keybinding/XEH_preClientInit.sqf +++ b/addons/keybinding/XEH_preInit.sqf @@ -1,6 +1,8 @@ #include "script_component.hpp" SCRIPT(XEH_preInit); +if (!hasInterface) exitWith {}; + ADDON = false; // Load DIK to string conversion table. diff --git a/addons/keybinding/gui/gui.hpp b/addons/keybinding/gui/gui.hpp index e9005f850..cc84c134e 100644 --- a/addons/keybinding/gui/gui.hpp +++ b/addons/keybinding/gui/gui.hpp @@ -25,8 +25,6 @@ class RscListBoxKeys; /////////////////////////////////////////////////////////////////////////////// class RscDisplayConfigure { - onLoad = "[""onLoad"",_this,""RscDisplayConfigure"",'GUI'] call compile preprocessfilelinenumbers ""A3\ui_f\scripts\initDisplay.sqf""; _this call compile preprocessfilelinenumbers ""\x\cba\addons\keybinding\gui\initDisplay.sqf"""; - class controls { class CA_ButtonCancel: RscButtonMenuCancel { onButtonClick = "_this call cba_keybinding_fnc_onButtonClick_cancel"; diff --git a/addons/linux/$NOBIN$ b/addons/linux/$NOBIN$ new file mode 100644 index 000000000..e69de29bb diff --git a/addons/main/script_macros_common.hpp b/addons/main/script_macros_common.hpp index 574b2ad17..ba04036eb 100644 --- a/addons/main/script_macros_common.hpp +++ b/addons/main/script_macros_common.hpp @@ -714,8 +714,8 @@ Macro: GVARMAIN() #define PREP(var1) TRIPLES(ADDON,fnc,var1) = compile preProcessFileLineNumbers 'PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))' #define PREPMAIN(var1) TRIPLES(PREFIX,fnc,var1) = compile preProcessFileLineNumbers 'PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))' #else - #define PREP(var1) ['PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))', 'TRIPLES(ADDON,fnc,var1)'] call SLX_XEH_COMPILE_NEW - #define PREPMAIN(var1) ['PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))', 'TRIPLES(PREFIX,fnc,var1)'] call SLX_XEH_COMPILE_NEW + #define PREP(var1) ['PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))', 'TRIPLES(ADDON,fnc,var1)'] call CBA_fnc_compileFunction + #define PREPMAIN(var1) ['PATHTO_SYS(PREFIX,COMPONENT_F,DOUBLES(fnc,var1))', 'TRIPLES(PREFIX,fnc,var1)'] call CBA_fnc_compileFunction #endif #define FUNC(var1) TRIPLES(ADDON,fnc,var1) diff --git a/addons/settings/$PBOPREFIX$ b/addons/settings/$PBOPREFIX$ new file mode 100644 index 000000000..9795e7d6d --- /dev/null +++ b/addons/settings/$PBOPREFIX$ @@ -0,0 +1 @@ +x\cba\addons\settings diff --git a/addons/settings/CBA_Settings.hpp b/addons/settings/CBA_Settings.hpp new file mode 100644 index 000000000..b082261d7 --- /dev/null +++ b/addons/settings/CBA_Settings.hpp @@ -0,0 +1,54 @@ + +class CBA_Setting_Boolean_base { + type = "BOOLEAN"; + displayName = ""; + tooltip = ""; + defaultValue = 0; +}; + +class CBA_Setting_List_base { + type = "LIST"; + displayName = ""; + tooltip = ""; + values[] = {0,1}; + //valueNames[] = {"disabled","enabled"}; + defaultIndex = 0; +}; + +class CBA_Setting_Slider_base { + type = "SLIDER"; + displayName = ""; + tooltip = ""; + min = 0; + max = 100; + defaultValue = 50; +}; + +class CBA_Setting_Slider_2_base: CBA_Setting_Slider_base { + min = 0; + max = 1; + defaultValue = 0.5; + trailingDecimals = 2; +}; + +class CBA_Setting_Color_base { + type = "COLOR"; + displayName = ""; + tooltip = ""; + defaultValue[] = {1,1,1}; +}; + +class CBA_Setting_Color_Alpha_base: CBA_Setting_Color_base { + defaultValue[] = {1,1,1,1}; +}; + +class CBA_Settings { + class CBA { + displayName = "CBA"; + class CBA_TEST1: CBA_Setting_List_base {}; + class CBA_TEST2: CBA_Setting_Boolean_base {}; + class CBA_TEST3: CBA_Setting_Slider_base {}; + class CBA_TEST_C: CBA_Setting_Color_base { displayName = "Test Setting Color"; }; + class CBA_TEST_A: CBA_Setting_Color_Alpha_base { displayName = "Test Setting Color Alpha"; }; + }; +}; diff --git a/addons/settings/Cfg3DEN.hpp b/addons/settings/Cfg3DEN.hpp new file mode 100644 index 000000000..9d2f9c3b2 --- /dev/null +++ b/addons/settings/Cfg3DEN.hpp @@ -0,0 +1,25 @@ + +class Cfg3DEN { + class Mission { + class Scenario { + class AttributeCategories { + class Presentation { // any existing + class Attributes { + class BriefingName; + class Author; // needed, to put blank space at the end. for looks + class GVAR(missionSettings) { + property = QGVAR(missionSettings); + value = 0; + control = "Default"; // blank space. not editable by hand + displayName = ""; + tooltip = ""; + defaultValue = "[]"; + expression = QUOTE(missionNamespace setVariable [ARR_3(QUOTE(QGVAR(3denSettings)),_value,true)]); + wikiType = "[[Array]]"; + }; + }; + }; + }; + }; + }; +}; diff --git a/addons/settings/CfgEventHandlers.hpp b/addons/settings/CfgEventHandlers.hpp new file mode 100644 index 000000000..6af958894 --- /dev/null +++ b/addons/settings/CfgEventHandlers.hpp @@ -0,0 +1,27 @@ + +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preStart)); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_postInit)); + }; +}; + +class Extended_DisplayLoad_EventHandlers { + class RscDisplayGameOptions { + ADDON = QUOTE(_this call COMPILE_FILE(gui\gui_initDisplay)); + }; + class Display3DEN { + ADDON = QUOTE(_this call COMPILE_FILE(init_3den)); + }; +}; diff --git a/addons/settings/CfgFunctions.hpp b/addons/settings/CfgFunctions.hpp new file mode 100644 index 000000000..85ab9fae8 --- /dev/null +++ b/addons/settings/CfgFunctions.hpp @@ -0,0 +1,10 @@ + +#define F_FILEPATH(func) class func {\ + file = QUOTE(PATHTOF(DOUBLES(fnc,func).sqf));\ +} + +class CfgFunctions { + class CBA { + class Settings {}; + }; +}; diff --git a/addons/settings/XEH_PREP.sqf b/addons/settings/XEH_PREP.sqf new file mode 100644 index 000000000..736c13bd5 --- /dev/null +++ b/addons/settings/XEH_PREP.sqf @@ -0,0 +1,18 @@ + +PREP(init); +PREP(set); +PREP(get); +PREP(check); +PREP(parse); +PREP(import); +PREP(export); +PREP(clear); +PREP(saveTempData); +PREP(isForced); +PREP(isOverwritten); +PREP(create); + +PREP(gui_addonChanged); +PREP(gui_sourceChanged); +PREP(gui_configure); +PREP(gui_closeMenu); diff --git a/addons/settings/XEH_postInit.sqf b/addons/settings/XEH_postInit.sqf new file mode 100644 index 000000000..b2045fe27 --- /dev/null +++ b/addons/settings/XEH_postInit.sqf @@ -0,0 +1,9 @@ +#include "script_component.hpp" +SCRIPT(XEH_postInit); + +// refresh all settings after postInit to guarantee that events are added +{ + { + [QGVAR(refreshSetting), _x] call CBA_fnc_localEvent; + } forEach GVAR(allSettings); +} call CBA_fnc_execNextFrame; diff --git a/addons/settings/XEH_preInit.sqf b/addons/settings/XEH_preInit.sqf new file mode 100644 index 000000000..860753de2 --- /dev/null +++ b/addons/settings/XEH_preInit.sqf @@ -0,0 +1,52 @@ +#include "script_component.hpp" +SCRIPT(XEH_preInit); + +ADDON = false; + +#include "XEH_PREP.sqf" + +call FUNC(init); + +// event to refresh missionNamespace value if setting has changed and call public event +[QGVAR(refreshSetting), { + params ["_setting"]; + private _value = _setting call FUNC(get); + + missionNamespace setVariable [_setting, _value]; + ["CBA_SettingChanged", [_setting, _value]] call CBA_fnc_localEvent; +}] call CBA_fnc_addEventHandler; + +// event to refresh all settings at once - saves bandwith +[QGVAR(refreshAllSettings), { + { + [QGVAR(refreshSetting), _x] call CBA_fnc_globalEvent; + } forEach GVAR(allSettings); +}] call CBA_fnc_addEventHandler; + +#ifdef DEBUG_MODE_FULL +["CBA_SettingChanged", { + params ["_setting", "_value"]; + + private _message = format ["[CBA] (settings): %1 = %2", _setting, _value]; + systemChat _message; + diag_log text _message; +}] call CBA_fnc_addEventHandler; +#endif + +// event to modify settings on a dedicated server as admin +if (isServer) then { + [QGVAR(setSettingServer), { + params ["_setting", "_value", "_forced"]; + [_setting, _value, _forced, "server"] call FUNC(set); + }] call CBA_fnc_addEventHandler; +}; + +// import settings from file if filepatching is enabled +if (isFilePatchingEnabled) then { + [loadFile PATH_SETTINGS_FILE, "client"] call FUNC(import); + diag_log text "[CBA] (settings): Settings file loaded."; +} else { + diag_log text "[CBA] (settings): Cannot load settings file. File patching disabled. Use -filePatching flag."; +}; + +ADDON = true; diff --git a/addons/settings/XEH_preStart.sqf b/addons/settings/XEH_preStart.sqf new file mode 100644 index 000000000..4af5b54ab --- /dev/null +++ b/addons/settings/XEH_preStart.sqf @@ -0,0 +1,4 @@ +#include "script_component.hpp" +SCRIPT(XEH_preStart); + +#include "XEH_PREP.sqf" diff --git a/addons/settings/config.cpp b/addons/settings/config.cpp new file mode 100644 index 000000000..be2239d65 --- /dev/null +++ b/addons/settings/config.cpp @@ -0,0 +1,21 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"CBA_common", "A3_UI_F"}; + version = VERSION; + author[] = {"commy2"}; + authorUrl = "https://github.com/CBATeam/CBA_A3"; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgFunctions.hpp" + +#include "CBA_Settings.hpp" +#include "Cfg3DEN.hpp" + +#include "gui\gui.hpp" diff --git a/addons/settings/fnc_check.sqf b/addons/settings/fnc_check.sqf new file mode 100644 index 000000000..c90b0ff4b --- /dev/null +++ b/addons/settings/fnc_check.sqf @@ -0,0 +1,40 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_check + +Description: + Check if provided value is valid. + +Parameters: + _setting - Name of the setting + _value - Value of to test + +Returns: + All setting info. Additionally to being put into clipboard + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_setting", "", [""]], "_value"]; + +if (isNil "_value") exitWith {false}; + +(GVAR(defaultSettings) getVariable _setting) params ["_defaultValue", "", "_settingType", "_values"]; + +switch (toUpper _settingType) do { + case ("BOOLEAN"): { + _value isEqualType false + }; + case ("LIST"): { + _value in _values + }; + case ("SLIDER"): { + _values params ["_min", "_max"]; + _value isEqualType 0 && {_value >= _min} && {_value <= _max} + }; + case ("COLOR"): { + _value isEqualType [] && {count _value == count _defaultValue} && {{_x < 0 || _x > 1} count _value == 0} + }; + default {false}; +}; diff --git a/addons/settings/fnc_clear.sqf b/addons/settings/fnc_clear.sqf new file mode 100644 index 000000000..57cfa8183 --- /dev/null +++ b/addons/settings/fnc_clear.sqf @@ -0,0 +1,49 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_clear + +Description: + Clear all settings from profile or mission. + +Parameters: + _source - Can be "client", "server" or "mission" (optional, default: "client") + +Returns: + None + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_source", "client", [""]]]; + +switch (toLower _source) do { + case ("client"): { + profileNamespace setVariable [QGVAR(profileSettings), []]; + + GVAR(clientSettings) call (uiNamespace getVariable "CBA_fnc_deleteNamespace"); + GVAR(clientSettings) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); + }; + case ("server"): { + if (isServer) then { + GVAR(serverSettings) call (uiNamespace getVariable "CBA_fnc_deleteNamespace"); + GVAR(serverSettings) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); + }; + }; + case ("mission"): { + if (is3DEN) then { + set3DENMissionAttributes [["Scenario", QGVAR(missionSettings), []]]; + GVAR(missionSettings) call (uiNamespace getVariable "CBA_fnc_deleteNamespace"); + GVAR(missionSettings) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); + }; + }; + default {}; +}; + +if (isServer) then { + QGVAR(refreshAllSettings) call CBA_fnc_globalEvent; +} else { + QGVAR(refreshAllSettings) call CBA_fnc_localEvent; +}; + +nil diff --git a/addons/settings/fnc_create.sqf b/addons/settings/fnc_create.sqf new file mode 100644 index 000000000..b32b8a69d --- /dev/null +++ b/addons/settings/fnc_create.sqf @@ -0,0 +1,149 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_create + +Description: + Creates a new setting for that session. + +Parameters: + _addon - Addon the setting to be creates belongs to. Used to organize settings menu + _setting - Unique setting name. Matches resulting variable name + _settingType - Type of setting. Can be "BOOLEAN", "LIST", "SLIDER" or "COLOR" + _title - Display name or display name + tooltip (optional, default: same as setting name) + _valueInfo - Extra properties of the setting depending of _settingType. See examples below + +Returns: + None + +Examples: + (begin example) + // CHECKBOX --- extra argument: default value + ["Mission Settings", "Test_Setting_1", "BOOLEAN", ["-test checkbox-", "-tooltip-"], true] call cba_settings_fnc_create; + + // LIST --- extra arguments: [_values, _valueTitles, _defaultIndex] + ["Mission Settings", "Test_Setting_2", "LIST", ["-test list-", "-tooltip-"], [[1,0], ["enabled","disabled"], 1]] call cba_settings_fnc_create; + + // SLIDER --- extra arguments: [_min, _max, _default, _trailingDecimals] + ["Mission Settings", "Test_Setting_3", "SLIDER", ["-test slider-", "-tooltip-"], [0, 10, 5, 0]] call cba_settings_fnc_create; + + // COLOR PICKER --- extra argument: _color + ["Mission Settings", "Test_Setting_4", "COLOR", ["-test color-", "-tooltip-"], [1,1,0]] call cba_settings_fnc_create; + (end) + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +if (isNil QGVAR(allSettings)) exitWith { + // this makes this function save to be used in preInit without having "CBA_settings" as required addon + _this spawn { + { + _this call FUNC(create); + } call CBA_fnc_directCall; + }; +}; + +params [ + ["_addon", "", [""]], + ["_setting", "", [""]], + ["_settingType", "", [""]], + ["_title", [], ["", []]], + ["_valueInfo", []] +]; +_title params [["_displayName", nil, [""]], ["_tooltip", "", [""]]]; + +if (_addon isEqualTo "" || _setting isEqualTo "") exitWith {false}; + +if (_displayName isEqualTo "") then { + _displayName = _setting; +}; + +private ["_defaultValue", "_values", "_valueNames", "_trailingDecimals"]; + +switch (toUpper _settingType) do { + case ("BOOLEAN"): { + _defaultValue = _valueInfo param [0, false, [false]]; // don't use params - we want these variables to be private to the main scope + _values = [_defaultValue, !_defaultValue]; + }; + case ("LIST"): { + _values = _valueInfo param [0, [], [[]]]; + _valueNames = _valueInfo param [1, [], [[]]]; + private _defaultIndex = _valueInfo param [2, 0, [0]]; + + _valueNames resize count _values; + { + if (isNil "_x") then { _x = _values select _forEachIndex }; + if !(_x isEqualType "") then { _x = str _x }; + if ((_x select [0, 1]) isEqualTo "$") then { + _x = _x select [1]; + if (isLocalized _x) then { _x = localize _x }; + }; + _valueNames set [_forEachIndex, _x]; + } forEach _valueNames; + + _defaultValue = _values param [_defaultIndex, 0]; + }; + case ("SLIDER"): { + _valueInfo params [ + ["_min", 0, [0]], + ["_max", 1, [0]] + ]; + _defaultValue = _valueInfo param [2, 0, [0]]; + _trailingDecimals = _valueInfo param [3, 2, [0]]; + _values = [_min, _max]; + }; + case ("COLOR"): { + _defaultValue = [_valueInfo] param [0, [1,1,1], [[]], [2,3]]; + }; + default {}; +}; + +if (isNil "_defaultValue") exitWith {false}; + +GVAR(defaultSettings) setVariable [_setting, [_defaultValue, _addon, _settingType, _values, _valueNames, _displayName, _tooltip, _trailingDecimals]]; +GVAR(allSettings) pushBackUnique _setting; + +// read previous setting values from profile +(profileNamespace getVariable [QGVAR(profileSettings), []]) params [["_profileSettings", []], ["_profileValues", []], ["_profileForced", []]]; + +private _index = (_profileSettings apply {toLower _x}) find toLower _setting; + +if (_index != -1) then { + private _value = _profileValues param [_index]; + private _forced = _profileForced param [_index, false]; + + if !([_setting, _value] call FUNC(check)) then { + _value = [_setting, "default"] call FUNC(get); + + [_setting, _value, _forced, "client"] call FUNC(set); + diag_log text format ["[CBA] (settings): Invalid value for setting %1. Fall back to default value.", str _setting]; + }; + + GVAR(clientSettings) setVariable [_setting, [_value, _forced]]; + if (isServer && {isMultiplayer}) then { + GVAR(serverSettings) setVariable [_setting, [_value, _forced], true]; + }; +}; + +private _missionSettingsVar = missionNamespace getVariable [QGVAR(3denSettings), "Scenario" get3DENMissionAttribute QGVAR(missionSettings)]; +_missionSettingsVar params [["_missionSettings", []], ["_missionValues", []], ["_missionForced", []]]; + +_index = (_missionSettings apply {toLower _x}) find toLower _setting; + +if (_index != -1) then { + private _value = _missionValues param [_index]; + private _forced = _missionForced param [_index, false]; + + if !([_setting, _value] call FUNC(check)) then { + GVAR(missionSettings) setVariable [_setting, [_value, _forced]]; + }; +}; + +// refresh +if (isServer) then { + [QGVAR(refreshSetting), _setting] call CBA_fnc_globalEvent; +} else { + [QGVAR(refreshSetting), _setting] call CBA_fnc_localEvent; +}; + +true diff --git a/addons/settings/fnc_export.sqf b/addons/settings/fnc_export.sqf new file mode 100644 index 000000000..0f8a5ea1a --- /dev/null +++ b/addons/settings/fnc_export.sqf @@ -0,0 +1,42 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_export + +Description: + Copy all setting info into clipboard. + +Parameters: + _source - Can be "client", "server" or "mission" (optional, default: "client") + +Returns: + All setting info. Additionally to being put into clipboard + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +#define NEWLINE toString [10] +#define KEYWORD_FORCE "force" + +params [["_source", "client", [""]]]; + +private _info = []; + +{ + private _value = [_x, _source] call FUNC(get); + private _forced = [_x, _source] call FUNC(isForced); + + _info pushBack [_x, _value, _forced]; +} forEach GVAR(allSettings); + +// get into readable format +private _formattedInfo = ""; + +{ + _x params ["_setting", "_value", "_forced"]; + _formattedInfo = _formattedInfo + (["", KEYWORD_FORCE + " "] select _forced) + _setting + " = " + format ["%1", _value] + ";" + NEWLINE; +} forEach _info; + +copyToClipboard _formattedInfo; + +_info diff --git a/addons/settings/fnc_get.sqf b/addons/settings/fnc_get.sqf new file mode 100644 index 000000000..721a462b1 --- /dev/null +++ b/addons/settings/fnc_get.sqf @@ -0,0 +1,63 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_get + +Description: + Returns the value of a setting. + +Parameters: + _setting - Name of the setting + _source - Can be "server", "mission", "client", "forced" or "default" (optional, default: "forced") + +Returns: + Value of the setting + +Examples: + (begin example) + _result = "CBA_TestSetting" call CBA_settings_fnc_get + (end) + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_setting", "", [""]], ["_source", "forced", [""]]]; + +private _value = switch (toLower _source) do { + case ("client"): { + (GVAR(clientSettings) getVariable _setting) param [0] + }; + case ("server"): { + (GVAR(serverSettings) getVariable _setting) param [0] + }; + case ("mission"): { + (GVAR(missionSettings) getVariable _setting) param [0] + }; + case ("default"): { + (GVAR(defaultSettings) getVariable _setting) param [0] + }; + case ("forced"): { + private "_value"; + + { + if ([_setting, _x] call FUNC(isForced)) exitWith { + _value = [_setting, _x] call FUNC(get); + }; + } forEach ["server", "mission", "client"]; + + if (isNil "_value") then {nil} else {_value}; + }; + default { + _source = "default"; // exit + }; +}; + +if (isNil "_value") exitWith { + // setting does not seem to exist + if (_source == "default") exitWith {nil}; + + [_setting, "default"] call FUNC(get); +}; + +// copy array to prevent overwriting +if (_value isEqualType []) then {+_value} else {_value} diff --git a/addons/settings/fnc_gui_addonChanged.sqf b/addons/settings/fnc_gui_addonChanged.sqf new file mode 100644 index 000000000..be1d14fd9 --- /dev/null +++ b/addons/settings/fnc_gui_addonChanged.sqf @@ -0,0 +1,28 @@ +#include "script_component.hpp" + +// get button +params ["_control", "_index"]; + +// get dialog +private _display = ctrlParent _control; + +private _selectedAddon = uiNamespace getVariable (_control lbData _index); + +if (_selectedAddon isEqualType "") then { + uiNamespace setVariable [QGVAR(addon), _selectedAddon]; +}; + +uiNamespace setVariable [QGVAR(addonIndex), _index]; + +// toggle lists +private _selectedSource = uiNamespace getVariable QGVAR(source); + +{ + (_x splitString "$") params ["", "_addon", "_source"]; + + private _ctrlOptionsGroup = uiNamespace getVariable _x; + private _isSelected = _source == _selectedSource && {_addon == _selectedAddon}; + + _ctrlOptionsGroup ctrlEnable _isSelected; + _ctrlOptionsGroup ctrlShow _isSelected; +} forEach (uiNamespace getVariable QGVAR(lists)); diff --git a/addons/settings/fnc_gui_closeMenu.sqf b/addons/settings/fnc_gui_closeMenu.sqf new file mode 100644 index 000000000..e55446ff0 --- /dev/null +++ b/addons/settings/fnc_gui_closeMenu.sqf @@ -0,0 +1,31 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_gui_closeMenu + +Description: + Save settings and clean up temporary data. + +Parameters: + _save - Name of the setting + +Returns: + None + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_save", false, [false]]]; + +if (_save) then { + call FUNC(saveTempData); +}; + +GVAR(clientSettingsTemp) call (uiNamespace getVariable "CBA_fnc_deleteNamespace"); +GVAR(clientSettingsTemp) = nil; + +GVAR(serverSettingsTemp) call (uiNamespace getVariable "CBA_fnc_deleteNamespace"); +GVAR(serverSettingsTemp) = nil; + +GVAR(missionSettingsTemp) call (uiNamespace getVariable "CBA_fnc_deleteNamespace"); +GVAR(missionSettingsTemp) = nil; diff --git a/addons/settings/fnc_gui_configure.sqf b/addons/settings/fnc_gui_configure.sqf new file mode 100644 index 000000000..c588d6dc6 --- /dev/null +++ b/addons/settings/fnc_gui_configure.sqf @@ -0,0 +1,111 @@ +#include "script_component.hpp" + +// get button +params ["_control"]; + +// get dialog +private _display = ctrlParent _control; + +private _ctrlGeneralGroup = _display displayCtrl 2300; +private _ctrlColorsGroup = _display displayCtrl 2301; +private _ctrlDifficultyGroup = _display displayCtrl 2302; + +private _ctrlDifficultyButton = _display displayCtrl 304; +private _ctrlGeneralButton = _display displayCtrl 2402; +private _ctrlGUIButton = _display displayCtrl 2404; +private _ctrlLayoutButton = _display displayCtrl 2405; +private _ctrlTitle = _display displayCtrl 1000; +private _ctrlPresetsButton = _display displayCtrl 114; +private _ctrlDefaultButton = _display displayCtrl 101; + +private _ctrlAddonsGroup = _display displayCtrl IDC_ADDONS_GROUP; +private _ctrlToggleButton = _display displayCtrl IDC_BTN_CONFIGURE_ADDONS; +private _ctrlClientButton = _display displayCtrl IDC_BTN_CLIENT; +private _ctrlServerButton = _display displayCtrl IDC_BTN_SERVER; +private _ctrlMissionButton = _display displayCtrl IDC_BTN_MISSION; +private _ctrlButtonImport = _display displayCtrl IDC_BTN_IMPORT; +private _ctrlButtonExport = _display displayCtrl IDC_BTN_EXPORT; + +// Toggle displayed groups and buttons. +if !(ctrlShown _ctrlAddonsGroup) then { + //--- disable and hide default menu + _ctrlGeneralGroup ctrlEnable false; + _ctrlGeneralGroup ctrlShow false; + _ctrlColorsGroup ctrlEnable false; + _ctrlColorsGroup ctrlShow false; + _ctrlDifficultyGroup ctrlEnable false; + _ctrlDifficultyGroup ctrlShow false; + _ctrlPresetsButton ctrlEnable false; + _ctrlPresetsButton ctrlShow false; + _ctrlDefaultButton ctrlEnable false; + _ctrlDefaultButton ctrlShow false; + _ctrlDifficultyButton ctrlEnable false; + _ctrlDifficultyButton ctrlShow false; + _ctrlGeneralButton ctrlEnable false; + _ctrlGeneralButton ctrlShow false; + _ctrlGUIButton ctrlEnable false; + _ctrlGUIButton ctrlShow false; + _ctrlLayoutButton ctrlEnable false; + _ctrlLayoutButton ctrlShow false; + + //--- show and enable custom buttons + _ctrlAddonsGroup ctrlEnable true; + _ctrlAddonsGroup ctrlShow true; + _ctrlClientButton ctrlEnable CAN_VIEW_CLIENT_SETTINGS; + _ctrlClientButton ctrlShow true; + _ctrlServerButton ctrlEnable CAN_VIEW_SERVER_SETTINGS; + _ctrlServerButton ctrlShow true; + _ctrlMissionButton ctrlEnable CAN_VIEW_MISSION_SETTINGS; + _ctrlMissionButton ctrlShow true; + _ctrlButtonImport ctrlEnable true; + _ctrlButtonImport ctrlShow true; + _ctrlButtonExport ctrlEnable true; + _ctrlButtonExport ctrlShow true; + + //--- change button text + _ctrlToggleButton ctrlSetText localize LSTRING(configureBase); + + //--- emulate default scope selection + ([ + _ctrlClientButton, _ctrlServerButton, _ctrlMissionButton + ] param [[ + CAN_VIEW_CLIENT_SETTINGS, CAN_VIEW_SERVER_SETTINGS, CAN_VIEW_MISSION_SETTINGS + ] find true]) call FUNC(gui_sourceChanged); +} else { + //--- enable and show default menu + _ctrlGeneralGroup ctrlEnable true; + _ctrlGeneralGroup ctrlShow true; + _ctrlColorsGroup ctrlEnable false; + _ctrlColorsGroup ctrlShow false; + _ctrlDifficultyGroup ctrlEnable false; + _ctrlDifficultyGroup ctrlShow false; + _ctrlPresetsButton ctrlEnable true; + _ctrlPresetsButton ctrlShow true; + _ctrlDefaultButton ctrlEnable false; + _ctrlDefaultButton ctrlShow false; + _ctrlDifficultyButton ctrlEnable true; + _ctrlDifficultyButton ctrlShow true; + _ctrlGeneralButton ctrlEnable true; + _ctrlGeneralButton ctrlShow true; + _ctrlGUIButton ctrlEnable true; + _ctrlGUIButton ctrlShow true; + _ctrlLayoutButton ctrlEnable true; + _ctrlLayoutButton ctrlShow true; + + //--- hide and disable custom buttons + _ctrlAddonsGroup ctrlEnable false; + _ctrlAddonsGroup ctrlShow false; + _ctrlClientButton ctrlEnable false; + _ctrlClientButton ctrlShow false; + _ctrlServerButton ctrlEnable false; + _ctrlServerButton ctrlShow false; + _ctrlMissionButton ctrlEnable false; + _ctrlMissionButton ctrlShow false; + _ctrlButtonImport ctrlEnable false; + _ctrlButtonImport ctrlShow false; + _ctrlButtonExport ctrlEnable false; + _ctrlButtonExport ctrlShow false; + + //--- change button text + _ctrlToggleButton ctrlSetText localize LSTRING(configureAddons); +}; diff --git a/addons/settings/fnc_gui_sourceChanged.sqf b/addons/settings/fnc_gui_sourceChanged.sqf new file mode 100644 index 000000000..7128f8408 --- /dev/null +++ b/addons/settings/fnc_gui_sourceChanged.sqf @@ -0,0 +1,33 @@ +#include "script_component.hpp" + +// get button +params ["_control"]; + +// get dialog +private _display = ctrlParent _control; + +private _selectedSource = ["client", "server", "mission"] param [[IDC_BTN_CLIENT, IDC_BTN_SERVER, IDC_BTN_MISSION] find ctrlIDC _control]; + +uiNamespace setVariable [QGVAR(source), _selectedSource]; + +private _selectedAddon = uiNamespace getVariable QGVAR(addon); + +// toggle lists +{ + (_x splitString "$") params ["", "_addon", "_source"]; + + private _ctrlOptionsGroup = uiNamespace getVariable _x; + private _isSelected = _source == _selectedSource && {_addon == _selectedAddon}; + + _ctrlOptionsGroup ctrlEnable _isSelected; + _ctrlOptionsGroup ctrlShow _isSelected; +} forEach (uiNamespace getVariable QGVAR(lists)); + +// toggle source buttons +{ + private _ctrlX = _display displayCtrl _x; + _ctrlX ctrlSetTextColor ([COLOR_BUTTON_ENABLED, COLOR_BUTTON_DISABLED] select (_control == _ctrlX)); + _ctrlX ctrlSetBackgroundColor ([COLOR_BUTTON_DISABLED, COLOR_BUTTON_ENABLED] select (_control == _ctrlX)); +} forEach [IDC_BTN_CLIENT, IDC_BTN_SERVER, IDC_BTN_MISSION]; + +(_display displayCtrl IDC_TXT_FORCE) ctrlShow (_selectedSource != "client"); diff --git a/addons/settings/fnc_import.sqf b/addons/settings/fnc_import.sqf new file mode 100644 index 000000000..9b1ddfb36 --- /dev/null +++ b/addons/settings/fnc_import.sqf @@ -0,0 +1,33 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_import + +Description: + Import all setting info. + +Parameters: + _info - Formated settings info, (from CBA_settings_fnc_export), (optional, default: clipboard) + +Returns: + true if successful, otherwise false + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_info", "", [""]], ["_source", "client", [""]]]; + +_info = _info call FUNC(parse); + +diag_log text format ["[CBA] (settings): Importing settings..."]; + +{ + _x params ["_setting", "_value", "_force"]; + + SET_TEMP_NAMESPACE_VALUE(_setting,_value,_source); + SET_TEMP_NAMESPACE_FORCED(_setting,_force,_source); +} forEach _info; + +call FUNC(saveTempData); + +(uiNamespace getVariable [QGVAR(display), displayNull]) closeDisplay 0; diff --git a/addons/settings/fnc_init.sqf b/addons/settings/fnc_init.sqf new file mode 100644 index 000000000..ee328a467 --- /dev/null +++ b/addons/settings/fnc_init.sqf @@ -0,0 +1,148 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_init + +Description: + Init settings. + +Parameters: + None + +Returns: + None + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +if (isNil QGVAR(defaultSettings)) then { + // settings can be set in the main menu. have to use ui namespace copies of the functions + GVAR(defaultSettings) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); + GVAR(allSettings) = []; // same as allVariables GVAR(defaultSettings), but case sensitive + + { + private _addon = configName _x; + + { + private _setting = configName _x; + private _settingType = getText (_x >> "type"); + private _displayName = getText (_x >> "displayName"); + private _tooltip = getText (_x >> "tooltip"); + + if (_displayName isEqualTo "") then { + _displayName = _setting; + }; + + private ["_defaultValue", "_values", "_valueNames", "_trailingDecimals"]; + + switch (toUpper _settingType) do { + case ("BOOLEAN"): { + _defaultValue = getNumber (_x >> "defaultValue") == 1; + _values = [_defaultValue, !_defaultValue]; + }; + case ("LIST"): { + _values = getArray (_x >> "values"); + _valueNames = getArray (_x >> "valueNames"); + _valueNames resize count _values; + { + if (isNil "_x") then { _x = _values select _forEachIndex }; + if !(_x isEqualType "") then { _x = str _x }; + if ((_x select [0, 1]) isEqualTo "$") then { + _x = _x select [1]; + if (isLocalized _x) then { _x = localize _x }; + }; + _valueNames set [_forEachIndex, _x]; + } forEach _valueNames; + + _defaultValue = _values param [getNumber (_x >> "defaultIndex"), 0]; + }; + case ("SLIDER"): { + _values = [getNumber (_x >> "min"), getNumber (_x >> "max")]; + _defaultValue = getNumber (_x >> "defaultValue"); + _trailingDecimals = getNumber (_x >> "trailingDecimals"); + }; + case ("COLOR"): { + _defaultValue = getArray (_x >> "defaultValue"); + }; + default {}; + }; + + GVAR(defaultSettings) setVariable [_setting, [_defaultValue, _addon, _settingType, _values, _valueNames, _displayName, _tooltip, _trailingDecimals]]; + GVAR(allSettings) pushBack _setting; + } forEach ("true" configClasses _x); + } forEach ("true" configClasses (configFile >> "CBA_Settings")); +}; + +if (isNil QGVAR(clientSettings)) then { + // retrieve client settings from profile + GVAR(clientSettings) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); + + (profileNamespace getVariable [QGVAR(profileSettings), []]) params [["_clientSettings", []], ["_clientValues", []], ["_clientForced", []]]; + + { + private _setting = _x; + private _value = _clientValues param [_forEachIndex]; + private _forced = _clientForced param [_forEachIndex, false]; + + if (!isNil {GVAR(defaultSettings) getVariable _setting}) then { + if !([_setting, _value] call FUNC(check)) then { + _value = [_setting, "default"] call FUNC(get); + + [_setting, _value, _forced, "client"] call FUNC(set); + diag_log text format ["[CBA] (settings): Invalid value for setting %1. Fall back to default value.", str _setting]; + }; + + GVAR(clientSettings) setVariable [_setting, [_value, _forced]]; + }; + } forEach _clientSettings; +}; + +if (isNil QGVAR(serverSettings) && {isServer && {isMultiplayer}}) then { + // retrieve client settings from profile + GVAR(serverSettings) = true call (uiNamespace getVariable "CBA_fnc_createNamespace"); + + (profileNamespace getVariable [QGVAR(profileSettings), []]) params [["_serverSettings", []], ["_serverValues", []], ["_serverForced", []]]; + + { + private _setting = _x; + private _value = _serverValues param [_forEachIndex]; + private _forced = _serverForced param [_forEachIndex, false]; + + if (!isNil {GVAR(defaultSettings) getVariable _setting} && {[_setting, _value] call FUNC(check)}) then { + GVAR(serverSettings) setVariable [_setting, [_value, _forced], true]; + }; + } forEach _serverSettings; +}; + +// delay a frame, because "get3DENMissionAttribute" (and "is3DEN") are not working on preInit when +// returning from a preview (they do when entering the editor from the main menu though) +// use spawn-directCall, because CBA_fnc_execNextFrame stalls until after postInit +0 spawn { + { + if (isNil QGVAR(missionSettings)) then { + // retrieve mission settings from 3den mission + GVAR(missionSettings) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); + + private _missionSettingsVar = missionNamespace getVariable [QGVAR(3denSettings), "Scenario" get3DENMissionAttribute QGVAR(missionSettings)]; + _missionSettingsVar params [["_missionSettings", []], ["_missionValues", []], ["_missionForced", []]]; + + { + private _setting = _x; + private _value = _missionValues param [_forEachIndex]; + private _forced = _missionForced param [_forEachIndex, false]; + + if (!isNil {GVAR(defaultSettings) getVariable _setting} && [_setting, _value] call FUNC(check)) then { + GVAR(missionSettings) setVariable [_setting, [_value, _forced]]; + }; + } forEach _missionSettings; + }; + + // set local values now, but don't do events. this is so these don't remain undefined + { + private _setting = _x; + private _value = _setting call FUNC(get); + + missionNamespace setVariable [_setting, _value]; + } forEach GVAR(allSettings); + } call (uiNamespace getVariable "CBA_fnc_directCall"); +}; diff --git a/addons/settings/fnc_isForced.sqf b/addons/settings/fnc_isForced.sqf new file mode 100644 index 000000000..aeeb22a4a --- /dev/null +++ b/addons/settings/fnc_isForced.sqf @@ -0,0 +1,32 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_isForced + +Description: + Check if setting is forced. + +Parameters: + _setting - Name of the setting + _source - Can be "client", "server" or "mission" (optional, default: "client") + +Returns: + _forced - Whether or not the setting is forced + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_setting", "", [""]], ["_source", "client", [""]]]; + +switch (toLower _source) do { + case ("client"): { + [GVAR(clientSettings) getVariable _setting] param [0, []] param [1, false] + }; + case ("server"): { + [GVAR(serverSettings) getVariable _setting] param [0, []] param [1, false] + }; + case ("mission"): { + [GVAR(missionSettings) getVariable _setting] param [0, []] param [1, false] + }; + default {nil}; +}; diff --git a/addons/settings/fnc_isOverwritten.sqf b/addons/settings/fnc_isOverwritten.sqf new file mode 100644 index 000000000..84157b209 --- /dev/null +++ b/addons/settings/fnc_isOverwritten.sqf @@ -0,0 +1,32 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_isOverwritten + +Description: + Check if setting is overwritten by higher priority source. + +Parameters: + _setting - Name of the setting + _source - Can be "client", "server" or "mission" (optional, default: "client") + +Returns: + _overwritten - Whether or not the setting is overwritten + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_setting", "", [""]], ["_source", "client", [""]]]; + +switch (toLower _source) do { + case ("client"): { + [_setting, "mission"] call FUNC(isForced) || {[_setting, "server"] call FUNC(isForced)} + }; + case ("server"): { + false + }; + case ("mission"): { + [_setting, "server"] call FUNC(isForced) + }; + default {nil}; +}; diff --git a/addons/settings/fnc_parse.sqf b/addons/settings/fnc_parse.sqf new file mode 100644 index 000000000..70cde973a --- /dev/null +++ b/addons/settings/fnc_parse.sqf @@ -0,0 +1,90 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_parse + +Description: + Copy all setting info into clipboard. + +Parameters: + _info - Content of file or clipboard to parse. + +Returns: + Settings with values and forced states. + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +#define ASCII_NEWLINE 10 +#define ASCII_CARRIAGE_RETURN 13 +#define ASCII_TAB 9 +#define ASCII_SPACE 32 + +#define WHITE_SPACE [ASCII_NEWLINE, ASCII_CARRIAGE_RETURN, ASCII_TAB, ASCII_SPACE] + +#define KEYWORD_FORCE "force" +#define QUOTE_MARKS toArray """'" +#define ALL_NUMBERS toArray "0123456789" +#define ASCII_ARRAY_OPEN (toArray "[" select 0) +#define ASCII_ARRAY_CLOSE (toArray "]" select 0) + +params [["_info", "", [""]]]; + +private _result = []; + +{ + private _statement = _x; + + private _force = false; + if ((_statement splitString toString WHITE_SPACE) param [0, ""] == KEYWORD_FORCE) then { + _force = true; + _statement = _statement select [(toLower _statement find KEYWORD_FORCE) + count KEYWORD_FORCE]; + }; + + _setting = ((_statement select [0, _statement find "="]) call (uiNamespace getVariable "CBA_fnc_leftTrim")) call (uiNamespace getVariable "CBA_fnc_rightTrim"); + _value = ((_statement select [(_statement find "=") + 1]) call (uiNamespace getVariable "CBA_fnc_leftTrim")) call (uiNamespace getVariable "CBA_fnc_rightTrim"); + + if (_setting != "") then { + private _value0 = toArray (_value select [0,1]) select 0; + private _valueE = toArray (_value select [count _value - 1]) select 0; + + _value = switch (true) do { + //--- boolean + case (_value == "true"): { + true + }; + case (_value == "false"): { + false + }; + //--- number + case (_value0 in ALL_NUMBERS): { + parseNumber _value + }; + //--- string + case (_value0 in QUOTE_MARKS && {_valueE in QUOTE_MARKS}): { + _value select [1, count _value - 2] + }; + //--- array + case (_value0 == ASCII_ARRAY_OPEN && {_valueE == ASCII_ARRAY_CLOSE}): { + // prevent abusing for SQF injection, by clearing white space -> no command syntax possible + _value = (_value splitString toString WHITE_SPACE) joinString ""; + call compile _value + }; + default {nil}; + }; + + private _currentValue = [_setting, "default"] call FUNC(get); + + if (isNil "_currentValue") then { + diag_log text format ["[CBA] (settings): Error parsing settings file. Setting %1 does not exist.", str _setting]; + } else { + if ([_setting, _value] call FUNC(check)) then { + _result pushBack [_setting, _value, _force]; + } else { + diag_log text format ["[CBA] (settings): Error parsing settings file. Value %1 is invalid for setting %2.", _value, str _setting]; + }; + }; + }; +} forEach (_info splitString ";"); + +_result diff --git a/addons/settings/fnc_saveTempData.sqf b/addons/settings/fnc_saveTempData.sqf new file mode 100644 index 000000000..fd2eca57a --- /dev/null +++ b/addons/settings/fnc_saveTempData.sqf @@ -0,0 +1,38 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_saveTempData + +Description: + Saves temporary settings after closing the ingame settings editor. + +Parameters: + None + +Returns: + None + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +{ + private _setting = _x; + + { + private _source = _x; + + if (toLower _setting in allVariables GET_TEMP_NAMESPACE(_source)) then { + (GET_TEMP_NAMESPACE(_source) getVariable _setting) params ["_value", "_forced"]; + + if (isNil "_value") then { + _value = [_setting, _source] call FUNC(get); + }; + + if (isNil "_forced") then { + _forced = [_setting, _source] call FUNC(isForced); + }; + + [_setting, _value, _forced, _source] call FUNC(set); + }; + } forEach ["client", "server", "mission"]; +} forEach GVAR(allSettings); diff --git a/addons/settings/fnc_set.sqf b/addons/settings/fnc_set.sqf new file mode 100644 index 000000000..61cc60721 --- /dev/null +++ b/addons/settings/fnc_set.sqf @@ -0,0 +1,105 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_set + +Description: + Set the value of a setting. + +Parameters: + _setting - Name of the setting + _value - Value of the setting + _forced - Force setting? + _source - Can be "client", "server" or "mission" (optional, default: "client") + +Returns: + _success - Whether or not the provided value was valid + +Examples: + (begin example) + ["CBA_TestSetting", 1] call CBA_settings_fnc_set + (end) + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_setting", "", [""]], "_value", ["_forced", nil, [false]], ["_source", "client", [""]]]; + +if (!isNil "_value" && {!([_setting, _value] call FUNC(check))}) exitWith { + diag_log text format ["[CBA] (settings): Value %1 is invalid for setting %2.", _value, str _setting]; + false +}; + +if (isNil "_forced") then { + _forced = [_setting, _source] call FUNC(isForced); +}; + +switch (toLower _source) do { + case ("client"): { + // flag is used for server settings exclusively, keep previous state + _forced = [_setting, _source] call FUNC(isForced); + + GVAR(clientSettings) setVariable [_setting, [_value, _forced]]; + + (profileNamespace getVariable [QGVAR(profileSettings), []]) params [["_clientSettings", []], ["_clientValues", []], ["_clientForced", []]]; + private _index = _clientSettings find toLower _setting; + + if (_index == -1) then { + _index = count _clientSettings; + }; + + _clientSettings set [_index, toLower _setting]; + _clientValues set [_index, _value]; + _clientForced set [_index, _forced]; + + profileNamespace setVariable [QGVAR(profileSettings), [_clientSettings, _clientValues, _clientForced]]; + [QGVAR(refreshSetting), _setting] call CBA_fnc_localEvent; + }; + case ("server"): { + if (isMultiplayer) then { + if (isServer) then { + GVAR(serverSettings) setVariable [_setting, [_value, _forced], true]; + + (profileNamespace getVariable [QGVAR(profileSettings), []]) params [["_serverSettings", []], ["_serverValues", []], ["_serverForced", []]]; + private _index = _serverSettings find toLower _setting; + + if (_index == -1) then { + _index = count _serverSettings; + }; + + _serverSettings set [_index, toLower _setting]; + _serverValues set [_index, _value]; + _serverForced set [_index, _forced]; + + profileNamespace setVariable [QGVAR(profileSettings), [_serverSettings, _serverValues, _serverForced]]; + [QGVAR(refreshSetting), _setting] call CBA_fnc_globalEvent; + } else { + if (serverCommandAvailable "#logout") then { + [QGVAR(setSettingServer), [_setting, _value, _forced]] call CBA_fnc_serverEvent; + }; + }; + }; + }; + case ("mission"): { + if (is3DEN) then { + GVAR(missionSettings) setVariable [_setting, [_value, _forced]]; + + ("Scenario" get3DENMissionAttribute QGVAR(missionSettings)) params [["_missionSettings", []], ["_missionValues", []], ["_missionForced", []]]; + private _index = _missionSettings find toLower _setting; + + if (_index == -1) then { + _index = count _missionSettings; + }; + + _missionSettings set [_index, toLower _setting]; + _missionValues set [_index, _value]; + _missionForced set [_index, _forced]; + + set3DENMissionAttributes [["Scenario", QGVAR(missionSettings), [_missionSettings, _missionValues, _missionForced]]]; + [QGVAR(refreshSetting), _setting] call CBA_fnc_localEvent; + }; + }; + default {}; +}; + +true diff --git a/addons/settings/gui/gui.hpp b/addons/settings/gui/gui.hpp new file mode 100644 index 000000000..d92198fc8 --- /dev/null +++ b/addons/settings/gui/gui.hpp @@ -0,0 +1,142 @@ + +class RscControlsGroup { + class VScrollbar; + class HScrollbar; +}; + +class RscText; +class CBA_Rsc_SettingText: RscText { + style = 0x01; +}; + +class RscCombo; +class RscListNBox; +class RscButtonMenu; + +// can't set the colorDisable with SQF, so we have to create our own base classes when we want to use these with ctrlCreate +class RscXSliderH; +class CBA_Rsc_Slider_R: RscXSliderH { + color[] = {1,0,0,0.6}; + colorActive[] = {1,0,0,1}; + colorDisable[] = {1,0,0,0.4}; +}; +class CBA_Rsc_Slider_G: RscXSliderH { + color[] = {0,1,0,0.6}; + colorActive[] = {0,1,0,1}; + colorDisable[] = {0,1,0,0.4}; +}; +class CBA_Rsc_Slider_B: RscXSliderH { + color[] = {0,0,1,0.6}; + colorActive[] = {0,0,1,1}; + colorDisable[] = {0,0,1,0.4}; +}; + +class GVAR(OptionsGroup): RscControlsGroup { + class HScrollbar: HScrollbar { + height = 0; + }; + x = "0.5 * (((safezoneW / safezoneH) min 1.2) / 40)"; + y = "3.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + w = "35 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "13.8 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + lineHeight = "1 *((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + + class controls {}; // auto generated +}; + +// have to create to dynamically for every options group, because they would interfere with the controls groups otherwise +// has to be done, because scripted controls are always placed below regular (config) ones. +class GVAR(AddonsList): RscCombo { + linespacing = 1; + text = ""; + wholeHeight = "12 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + x = "4.5 * (((safezoneW / safezoneH) min 1.2) / 40)"; + y = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + w = "21 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; +}; + +class RscDisplayGameOptions { + class controls { + class CBA_ButtonConfigureAddons: RscButtonMenu { + idc = IDC_BTN_CONFIGURE_ADDONS; + text = CSTRING(configureAddons); + x = "20.15 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX)"; + y = "23 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))"; + w = "12.5 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + }; + + class CBA_ButtonClient: RscButtonMenu { + idc = IDC_BTN_CLIENT; + text = CSTRING(ButtonClient); + tooltip = CSTRING(ButtonClient_tooltip); + x = "1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX)"; + y = "2.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))"; + w = "8 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + }; + + class CBA_ButtonServer: CBA_ButtonClient { + idc = IDC_BTN_SERVER; + text = CSTRING(ButtonServer); + tooltip = CSTRING(ButtonServer_tooltip); + x = "9 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX)"; + }; + + class CBA_ButtonMission: CBA_ButtonClient { + idc = IDC_BTN_MISSION; + text = CSTRING(ButtonMission); + tooltip = CSTRING(ButtonMission_tooltip); + x = "17 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX)"; + }; + + class CBA_AddonsGroup: RscControlsGroup { + class VScrollbar: VScrollbar { + width = 0; + }; + class HScrollbar: HScrollbar { + height = 0; + }; + idc = IDC_ADDONS_GROUP; + enableDisplay = 0; + x = "1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX)"; + y = "3.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))"; + w = "38 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "17.3 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + + class controls { + class CBA_AddonsEmptyBackground: RscText { + idc = -1; + type = 0x00; + text = ""; + colorBackground[] = {0,0,0,0.4}; + x = "0.5 * (((safezoneW / safezoneH) min 1.2) / 40)"; + y = "3.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + w = "35 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "13.8 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + }; + class CBA_AddonsCA_ControlsPageText: RscText { + sizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)"; + style = 0x01; + idc = 2002; + text = "Addon:"; + x = "0.5 * (((safezoneW / safezoneH) min 1.2) / 40)"; + y = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + w = "4 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + }; + class CBA_ForceSettingText: RscText { + style = 0x01; + idc = IDC_TXT_FORCE; + text = ""; + tooltip = CSTRING(force_tooltip); + x = "25 * (((safezoneW / safezoneH) min 1.2) / 40)"; + y = "2.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + w = "10 * (((safezoneW / safezoneH) min 1.2) / 40)"; + h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; + }; + }; + }; + }; +}; diff --git a/addons/settings/gui/gui_createMenu.sqf b/addons/settings/gui/gui_createMenu.sqf new file mode 100644 index 000000000..0955b4d32 --- /dev/null +++ b/addons/settings/gui/gui_createMenu.sqf @@ -0,0 +1,104 @@ + +private _lists = []; + +uiNamespace setVariable [QGVAR(settingsControlsInfo), []]; + +{ + uiNamespace setVariable [_x, nil]; +} forEach (uiNamespace getVariable [QGVAR(offsets), []]); +uiNamespace setVariable [QGVAR(offsets), []]; + +{ + private _setting = _x; + (GVAR(defaultSettings) getVariable _setting) params ["_defaultValue", "_addon", "_settingType", "_values", "_valueNames", "_displayName", "_tooltip", "_trailingDecimals"]; + + private _addon = toLower _addon; + _addons pushBackUnique _addon; + + { + private _source = toLower _x; + private _currentValue = [_setting, _source] call FUNC(get); + + // ----- create or retrieve options "list" controls group + private _list = [QGVAR(list), _addon, _source] joinString "$"; + + private "_ctrlOptionsGroup"; + if !(_list in _lists) then { + _ctrlOptionsGroup = _display ctrlCreate [QGVAR(OptionsGroup), -1, _display displayCtrl IDC_ADDONS_GROUP]; + _ctrlOptionsGroup ctrlEnable false; + _ctrlOptionsGroup ctrlShow false; + _lists pushBack _list; + uiNamespace setVariable [_list, _ctrlOptionsGroup]; + } else { + _ctrlOptionsGroup = uiNamespace getVariable _list; + }; + + private _offsetY = uiNamespace getVariable OFFSETY(_addon,_source); + + if (isNil "_offsetY") then { + _offsetY = 0.3; + uiNamespace setVariable [OFFSETY(_addon,_source), _offsetY]; + (uiNamespace getVariable QGVAR(offsets)) pushBack OFFSETY(_addon,_source); + }; + + // ----- create setting name text + private _ctrlSettingName = _display ctrlCreate ["CBA_Rsc_SettingText", -1, _ctrlOptionsGroup]; + + _ctrlSettingName ctrlSetText format ["%1:", _displayName]; + _ctrlSettingName ctrlSetTooltip _tooltip; + _ctrlSettingName ctrlSetPosition [ + POS_X(1), + POS_Y(_offsetY), + POS_X(15), + POS_Y(1) + ]; + _ctrlSettingName ctrlCommit 0; + + // ----- check if setting can be altered + private _enabled = switch (toLower _source) do { + case ("client"): { + CAN_SET_CLIENT_SETTINGS + }; + case ("server"): { + CAN_SET_SERVER_SETTINGS + }; + case ("mission"): { + CAN_SET_MISSION_SETTINGS + }; + }; + + // ----- check if altering setting would have no effect + private _isOverwritten = [_setting, _source] call FUNC(isOverwritten); + + // ----- create setting changer control + private _settingsControlsInfo = uiNamespace getVariable QGVAR(settingsControlsInfo); + private _linkedControls = []; + + switch (toUpper _settingType) do { + case ("BOOLEAN"): { + #include "gui_createMenu_button.sqf" + }; + case ("LIST"): { + #include "gui_createMenu_list.sqf" + }; + case ("SLIDER"): { + #include "gui_createMenu_slider.sqf" + }; + case ("COLOR"): { + #include "gui_createMenu_color.sqf" + }; + default {}; + }; + + #include "gui_createMenu_default.sqf" + + // ----- handle "force" button + if (_source != "client") then { + #include "gui_createMenu_force.sqf" + }; + + uiNamespace setVariable [OFFSETY(_addon,_source), _offsetY + 1.4]; + } forEach ["client", "server", "mission"]; +} forEach GVAR(allSettings); + +uiNamespace setVariable [QGVAR(lists), _lists]; diff --git a/addons/settings/gui/gui_createMenu_button.sqf b/addons/settings/gui/gui_createMenu_button.sqf new file mode 100644 index 000000000..9fd6b07bc --- /dev/null +++ b/addons/settings/gui/gui_createMenu_button.sqf @@ -0,0 +1,35 @@ + +private _ctrlSetting = _display ctrlCreate ["RscCheckBox", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + +_ctrlSetting ctrlSetPosition [ + POS_X(16), + POS_Y(_offsetY), + POS_X(1), + POS_Y(1) +]; +_ctrlSetting ctrlCommit 0; +_ctrlSetting cbSetChecked _currentValue; + +_settingsControlsInfo pushBack [_linkedControls, _setting, _source]; + +_ctrlSetting ctrlAddEventHandler ["CheckedChanged", { + params ["_control", "_state"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "_setting", "_source"]; + + private _value = _state == 1; + SET_TEMP_NAMESPACE_VALUE(_setting,_value,_source); +}]; + +_linkedControls pushBack _ctrlSetting; + +if (_isOverwritten) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_OVERWRITTEN; + _ctrlSetting ctrlSetTooltip localize LSTRING(overwritten_tooltip); +}; + +if !(_enabled) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_DISABLED; + _ctrlSetting ctrlEnable false; +}; diff --git a/addons/settings/gui/gui_createMenu_color.sqf b/addons/settings/gui/gui_createMenu_color.sqf new file mode 100644 index 000000000..959aebeb4 --- /dev/null +++ b/addons/settings/gui/gui_createMenu_color.sqf @@ -0,0 +1,122 @@ + +#define SLIDER_TYPES ["CBA_Rsc_Slider_R", "CBA_Rsc_Slider_G", "CBA_Rsc_Slider_B"] +#define SLIDER_COLORS [[1,0,0,1], [0,1,0,1], [0,0,1,1], [1,1,1,1]] + +private _ctrlSettingPreview = _display ctrlCreate ["RscText", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + +_ctrlSettingPreview ctrlSetPosition [ + POS_X(9.5), + POS_Y(_offsetY + 1.0), + POS_X(6), + POS_Y(1) +]; +_ctrlSettingPreview ctrlCommit 0; + +_currentValue params [ + ["_r", 0, [0]], + ["_g", 0, [0]], + ["_b", 0, [0]], + ["_a", 1, [0]] +]; +private _color = [_r, _g, _b, _a]; +_ctrlSettingPreview ctrlSetBackgroundColor _color; + +_linkedControls append [_ctrlSettingPreview, []]; +_settingsControlsInfo pushBack [_linkedControls, _setting, _source, _currentValue, _color]; + +for "_index" from 0 to (((count _defaultValue max 3) min 4) - 1) do { + private _ctrlSetting = _display ctrlCreate [SLIDER_TYPES param [_index, "RscXSliderH"], count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + + _ctrlSetting ctrlSetPosition [ + POS_X(16), + POS_Y(_offsetY), + POS_X(8), + POS_Y(1) + ]; + _ctrlSetting ctrlCommit 0; + + _ctrlSetting sliderSetRange [0, 1]; + _ctrlSetting sliderSetPosition (_currentValue param [_index, 0]); + + _settingsControlsInfo pushBack [_linkedControls, _setting, _source, _currentValue, _color, _index, _ctrlSettingPreview]; + + _ctrlSetting ctrlAddEventHandler ["SliderPosChanged", { + params ["_control", "_value"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "_setting", "_source", "_currentValue", "_color", "_index", "_ctrlSettingPreview"]; + + private _linkedControl = _linkedControls select 1 select _index select 1; + _linkedControl ctrlSetText ([_value, 1, 2] call (uiNamespace getVariable "CBA_fnc_formatNumber")); + + _currentValue set [_index, _value]; + _color set [_index, _value]; + _ctrlSettingPreview ctrlSetBackgroundColor _color; + + SET_TEMP_NAMESPACE_VALUE(_setting,_currentValue,_source); + }]; + + private _ctrlSettingEdit = _display ctrlCreate ["RscEdit", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + + _ctrlSettingEdit ctrlSetPosition [ + POS_X(24), + POS_Y(_offsetY), + POS_X(2), + POS_Y(1) + ]; + _ctrlSettingEdit ctrlCommit 0; + + //_ctrlSettingEdit ctrlSetTextColor (SLIDER_COLORS param [_index, 0]); + _ctrlSettingEdit ctrlSetActiveColor (SLIDER_COLORS param [_index, 0]); + _ctrlSettingEdit ctrlSetText ([_currentValue param [_index, 0], 1, 2] call (uiNamespace getVariable "CBA_fnc_formatNumber")); + + _settingsControlsInfo pushBack [_linkedControls, _setting, _source, _currentValue, _color, _index, _ctrlSettingPreview]; + + _ctrlSettingEdit ctrlAddEventHandler ["KeyUp", { + params ["_control"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "_setting", "_source", "_currentValue", "_color", "_index", "_ctrlSettingPreview"]; + + private _value = parseNumber ctrlText _control; + + private _linkedControl = _linkedControls select 1 select _index select 0; + _linkedControl sliderSetPosition _value; + + _currentValue set [_index, sliderPosition _linkedControl]; + _color set [_index, _value]; + _ctrlSettingPreview ctrlSetBackgroundColor _color; + + SET_TEMP_NAMESPACE_VALUE(_setting,_currentValue,_source); + }]; + + _ctrlSettingEdit ctrlAddEventHandler ["KillFocus", { + params ["_control"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "", "", "", "", "_index"]; + + private _linkedControl = _linkedControls select 1 select _index select 0; + private _value = sliderPosition _linkedControl; + + _control ctrlSetText ([_value, 1, 2] call (uiNamespace getVariable "CBA_fnc_formatNumber")); + }]; + + (_linkedControls select 1) pushBack [_ctrlSetting, _ctrlSettingEdit]; + + if (_isOverwritten) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_OVERWRITTEN; + _ctrlSetting ctrlSetTooltip localize LSTRING(overwritten_tooltip); + _ctrlSettingEdit ctrlSetTooltip localize LSTRING(overwritten_tooltip); + }; + + if !(_enabled) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_DISABLED; + _ctrlSetting ctrlEnable false; + _ctrlSettingEdit ctrlEnable false; + }; + + _offsetY = _offsetY + 1.0; +}; + +_offsetY = _offsetY - 0.7; diff --git a/addons/settings/gui/gui_createMenu_default.sqf b/addons/settings/gui/gui_createMenu_default.sqf new file mode 100644 index 000000000..6ecfa77c6 --- /dev/null +++ b/addons/settings/gui/gui_createMenu_default.sqf @@ -0,0 +1,67 @@ + +private _ctrlSettingDefault = _display ctrlCreate ["RscButtonMenu", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + +_ctrlSettingDefault ctrlSetPosition [ + POS_X(27), + POS_Y(uiNamespace getVariable OFFSETY(_addon,_source)), + POS_X(5), + POS_Y(1) +]; +_ctrlSettingDefault ctrlCommit 0; +_ctrlSettingDefault ctrlSetText localize LSTRING(Default); + +_settingsControlsInfo pushBack [_linkedControls, _setting, _source, _defaultValue, _settingType, _values, _trailingDecimals]; + +_ctrlSettingDefault ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "_setting", "_source", "_defaultValue", "_settingType", "_values", "_trailingDecimals"]; + + SET_TEMP_NAMESPACE_VALUE(_setting,_defaultValue,_source); + + // reset buttons to default state + switch (toUpper _settingType) do { + case ("BOOLEAN"): { + _linkedControls params ["_ctrlSetting"]; + + _ctrlSetting cbSetChecked _defaultValue; + }; + case ("LIST"): { + _linkedControls params ["_ctrlSetting"]; + + _ctrlSetting lbSetCurSel (_values find _defaultValue); + }; + case ("SLIDER"): { + _linkedControls params ["_ctrlSetting", "_ctrlSettingEdit"]; + + _ctrlSetting sliderSetPosition _defaultValue; + _ctrlSettingEdit ctrlSetText ([_defaultValue, 1, _trailingDecimals] call (uiNamespace getVariable "CBA_fnc_formatNumber")); + }; + case ("COLOR"): { + _linkedControls params ["_ctrlSettingPreview", "_settingControls"]; + + _defaultValue params [ + ["_r", 0, [0]], + ["_g", 0, [0]], + ["_b", 0, [0]], + ["_a", 1, [0]] + ]; + private _color = [_r, _g, _b, _a]; + _ctrlSettingPreview ctrlSetBackgroundColor _color; + + { + _x params ["_ctrlSetting", "_ctrlSettingEdit"]; + private _value = _defaultValue select _forEachIndex; + + _ctrlSetting sliderSetPosition _value; + _ctrlSettingEdit ctrlSetText ([_value, 1, 2] call (uiNamespace getVariable "CBA_fnc_formatNumber")); + } forEach _settingControls; + }; + default {}; + }; +}]; + +if !(_enabled) then { + _ctrlSettingDefault ctrlEnable false; +}; diff --git a/addons/settings/gui/gui_createMenu_force.sqf b/addons/settings/gui/gui_createMenu_force.sqf new file mode 100644 index 000000000..01219cd51 --- /dev/null +++ b/addons/settings/gui/gui_createMenu_force.sqf @@ -0,0 +1,28 @@ + +private _ctrlSettingForce = _display ctrlCreate ["RscCheckBox", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + +_ctrlSettingForce ctrlSetPosition [ + POS_X(33), + POS_Y(uiNamespace getVariable OFFSETY(_addon,_source)), + POS_X(1), + POS_Y(1) +]; +_ctrlSettingForce ctrlCommit 0; +_ctrlSettingForce cbSetChecked ([_setting, _source] call FUNC(isForced)); + +_settingsControlsInfo pushBack [_linkedControls, _setting, _source]; + +_ctrlSettingForce ctrlAddEventHandler ["CheckedChanged", { + params ["_control", "_state"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["", "_setting", "_source"]; + + SET_TEMP_NAMESPACE_FORCED(_setting,_state == 1,_source); +}]; + +_linkedControls pushBack _ctrlSettingForce; + +if !(_enabled) then { + _ctrlSettingForce ctrlEnable false; +}; diff --git a/addons/settings/gui/gui_createMenu_list.sqf b/addons/settings/gui/gui_createMenu_list.sqf new file mode 100644 index 000000000..6c85d558c --- /dev/null +++ b/addons/settings/gui/gui_createMenu_list.sqf @@ -0,0 +1,44 @@ + +private _ctrlSetting = _display ctrlCreate ["RscCombo", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + +_ctrlSetting ctrlSetPosition [ + POS_X(16), + POS_Y(_offsetY), + POS_X(10), + POS_Y(1) +]; +_ctrlSetting ctrlCommit 0; + +private _data = []; + +{ + private _index = _ctrlSetting lbAdd (_valueNames select _forEachIndex); + _ctrlSetting lbSetData [_index, str _index]; + _data set [_index, _x]; +} forEach _values; + +_ctrlSetting lbSetCurSel (_values find _currentValue); + +_settingsControlsInfo pushBack [_linkedControls, _setting, _source, _data]; + +_ctrlSetting ctrlAddEventHandler ["LBSelChanged", { + params ["_control", "_index"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "_setting", "_source", "_data"]; + + private _value = _data select _index; + SET_TEMP_NAMESPACE_VALUE(_setting,_value,_source); +}]; + +_linkedControls pushBack _ctrlSetting; + +if (_isOverwritten) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_OVERWRITTEN; + _ctrlSetting ctrlSetTooltip localize LSTRING(overwritten_tooltip); +}; + +if !(_enabled) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_DISABLED; + _ctrlSetting ctrlEnable false; +}; diff --git a/addons/settings/gui/gui_createMenu_slider.sqf b/addons/settings/gui/gui_createMenu_slider.sqf new file mode 100644 index 000000000..2a7e10a15 --- /dev/null +++ b/addons/settings/gui/gui_createMenu_slider.sqf @@ -0,0 +1,82 @@ + +private _ctrlSetting = _display ctrlCreate ["RscXSliderH", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + +_ctrlSetting ctrlSetPosition [ + POS_X(16), + POS_Y(_offsetY), + POS_X(8), + POS_Y(1) +]; +_ctrlSetting ctrlCommit 0; + +_ctrlSetting sliderSetRange _values; +_ctrlSetting sliderSetPosition _currentValue; + +_settingsControlsInfo pushBack [_linkedControls, _setting, _source, _trailingDecimals]; + +_ctrlSetting ctrlAddEventHandler ["SliderPosChanged", { + params ["_control", "_value"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "_setting", "_source", "_trailingDecimals"]; + + private _linkedControl = _linkedControls select 1; + _linkedControl ctrlSetText ([_value, 1, _trailingDecimals] call (uiNamespace getVariable "CBA_fnc_formatNumber")); + + SET_TEMP_NAMESPACE_VALUE(_setting,_value,_source); +}]; + +private _ctrlSettingEdit = _display ctrlCreate ["RscEdit", count _settingsControlsInfo + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + +_ctrlSettingEdit ctrlSetPosition [ + POS_X(24), + POS_Y(_offsetY), + POS_X(2), + POS_Y(1) +]; +_ctrlSettingEdit ctrlCommit 0; +_ctrlSettingEdit ctrlSetText ([_currentValue, 1, _trailingDecimals] call (uiNamespace getVariable "CBA_fnc_formatNumber")); + +_settingsControlsInfo pushBack [_linkedControls, _setting, _source, _trailingDecimals]; + +_ctrlSettingEdit ctrlAddEventHandler ["KeyUp", { + params ["_control"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "_setting", "_source", "_trailingDecimals"]; + + private _value = parseNumber ctrlText _control; + + private _linkedControl = _linkedControls select 0; + _linkedControl sliderSetPosition _value; + + private _valueSlider = sliderPosition _linkedControl; + + SET_TEMP_NAMESPACE_VALUE(_setting,_valueSlider,_source); +}]; + +_ctrlSettingEdit ctrlAddEventHandler ["KillFocus", { + params ["_control"]; + + private _settingsControlsInfo = (uiNamespace getVariable QGVAR(settingsControlsInfo)) select (ctrlIDC _control - IDC_OFFSET_SETTING); + _settingsControlsInfo params ["_linkedControls", "", "", "_trailingDecimals"]; + + private _linkedControl = _linkedControls select 0; + private _value = sliderPosition _linkedControl; + + _control ctrlSetText ([_value, 1, _trailingDecimals] call (uiNamespace getVariable "CBA_fnc_formatNumber")); +}]; + +_linkedControls append [_ctrlSetting, _ctrlSettingEdit]; + +if (_isOverwritten) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_OVERWRITTEN; + _ctrlSetting ctrlSetTooltip localize LSTRING(overwritten_tooltip); + _ctrlSettingEdit ctrlSetTooltip localize LSTRING(overwritten_tooltip); +}; + +if !(_enabled) then { + _ctrlSettingName ctrlSetTextColor COLOR_TEXT_DISABLED; + _ctrlSetting ctrlEnable false; + _ctrlSettingEdit ctrlEnable false; +}; diff --git a/addons/settings/gui/gui_initDisplay.sqf b/addons/settings/gui/gui_initDisplay.sqf new file mode 100644 index 000000000..b1a9e065a --- /dev/null +++ b/addons/settings/gui/gui_initDisplay.sqf @@ -0,0 +1,100 @@ +#include "script_component.hpp" + +#define PREP(func) if (isNil QFUNC(func)) then {FUNC(func) = uiNamespace getVariable QFUNC(func)} +#include "..\XEH_PREP.sqf" +// -------------------------------------------------- + +call FUNC(init); + +params ["_display"]; + +uiNamespace setVariable [QGVAR(display), _display]; + +// ----- create addons list (filled later) +private _ctrlAddonsGroup = _display displayCtrl IDC_ADDONS_GROUP; +private _ctrlAddonList = _display ctrlCreate [QGVAR(AddonsList), -1, _ctrlAddonsGroup]; + +_ctrlAddonsGroup ctrlEnable false; +_ctrlAddonsGroup ctrlShow false; + +_ctrlAddonList ctrlAddEventHandler ["LBSelChanged", FUNC(gui_addonChanged)]; + +private _addons = []; + +// ----- create settings lists + +#include "gui_createMenu.sqf" + +// ----- fill addons list +{ + private _displayName = getText (configFile >> "CBA_Settings" >> _x >> "displayName"); + + if (_displayName isEqualTo "") then { + _displayName = _x; + }; + + private _index = _ctrlAddonList lbAdd _displayName; + private _indexStr = format [QGVAR(addon$%1), _index]; + + _ctrlAddonList lbSetData [_index, _indexStr]; + uiNamespace setVariable [_indexStr, _x]; +} forEach _addons; + +lbSort _ctrlAddonList; +_ctrlAddonList lbSetCurSel (uiNamespace getVariable [QGVAR(addonIndex), 0]); + +// ----- create export and import buttons +private _ctrlButtonImport = _display ctrlCreate ["RscButtonMenu", IDC_BTN_IMPORT]; + +_ctrlButtonImport ctrlSetPosition [ + 24.4 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX), + 20.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2)), + POS_X(6), + POS_Y(1) +]; + +_ctrlButtonImport ctrlCommit 0; +_ctrlButtonImport ctrlSetText localize LSTRING(ButtonImport); +_ctrlButtonImport ctrlSetTooltip localize LSTRING(ButtonImport_tooltip); +_ctrlButtonImport ctrlEnable false; +_ctrlButtonImport ctrlShow false; +_ctrlButtonImport ctrlAddEventHandler ["ButtonClick", {[copyFromClipboard, uiNamespace getVariable QGVAR(source)] call FUNC(import)}]; + +uiNamespace setVariable [QGVAR(ctrlButtonImport), _ctrlButtonImport]; + +private _ctrlButtonExport = _display ctrlCreate ["RscButtonMenu", IDC_BTN_EXPORT]; + +_ctrlButtonExport ctrlSetPosition [ + 30.5 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX), + 20.5 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2)), + POS_X(6), + POS_Y(1) +]; + +_ctrlButtonExport ctrlCommit 0; +_ctrlButtonExport ctrlSetText localize LSTRING(ButtonExport); +_ctrlButtonExport ctrlSetTooltip localize LSTRING(ButtonExport_tooltip); +_ctrlButtonExport ctrlEnable false; +_ctrlButtonExport ctrlShow false; +_ctrlButtonExport ctrlAddEventHandler ["ButtonClick", {[uiNamespace getVariable QGVAR(source)] call FUNC(export)}]; + +uiNamespace setVariable [QGVAR(ctrlButtonExport), _ctrlButtonExport]; + +// ----- source buttons (client, server, mission) +{ + _x ctrlEnable false; + _x ctrlShow false; + _x ctrlAddEventHandler ["ButtonClick", FUNC(gui_sourceChanged)]; +} forEach [_display displayCtrl IDC_BTN_CLIENT, _display displayCtrl IDC_BTN_SERVER, _display displayCtrl IDC_BTN_MISSION]; + +GVAR(clientSettingsTemp) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); +GVAR(serverSettingsTemp) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); +GVAR(missionSettingsTemp) = [] call (uiNamespace getVariable "CBA_fnc_createNamespace"); + +(_display displayCtrl IDC_BTN_CONFIGURE_ADDONS) ctrlAddEventHandler ["ButtonClick", FUNC(gui_configure)]; + +// ----- scripted OK button +(_display displayCtrl 999) ctrlAddEventHandler ["ButtonClick", {true call FUNC(gui_closeMenu)}]; + +// set this per script to avoid it being all upper case +(_display displayCtrl IDC_TXT_FORCE) ctrlSetText localize LSTRING(force); diff --git a/addons/settings/gui/script_component.hpp b/addons/settings/gui/script_component.hpp new file mode 100644 index 000000000..fcf9da986 --- /dev/null +++ b/addons/settings/gui/script_component.hpp @@ -0,0 +1 @@ +#include "..\script_component.hpp" diff --git a/addons/settings/init_3den.sqf b/addons/settings/init_3den.sqf new file mode 100644 index 000000000..d0abe074e --- /dev/null +++ b/addons/settings/init_3den.sqf @@ -0,0 +1,7 @@ +#include "script_component.hpp" + +// re-apply mission settings each time a mission is loaded +add3DENEventHandler ["onMissionLoad", { + GVAR(missionSettings) = nil; + call FUNC(init); +}]; diff --git a/addons/settings/license.txt b/addons/settings/license.txt new file mode 100644 index 000000000..434712527 --- /dev/null +++ b/addons/settings/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 CBA Project, Ryan Schultz + +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. \ No newline at end of file diff --git a/addons/settings/script_component.hpp b/addons/settings/script_component.hpp new file mode 100644 index 000000000..7e9a541ea --- /dev/null +++ b/addons/settings/script_component.hpp @@ -0,0 +1,53 @@ +#define COMPONENT settings +#include "\x\cba\addons\main\script_mod.hpp" +#include "\x\cba\addons\main\script_macros.hpp" + +//#define DEBUG_ENABLED_SETTINGS + +#ifdef DEBUG_ENABLED_SETTINGS + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_SETTINGS + #define DEBUG_SETTINGS DEBUG_SETTINGS_SETTINGS +#endif + +#define PATH_SETTINGS_FILE "userconfig\cba\settings.sqf" + +#define IDC_ADDONS_GROUP 4301 +#define IDC_BTN_CONFIGURE_ADDONS 4302 +#define IDC_BTN_CLIENT 9000 +#define IDC_BTN_SERVER 9001 +#define IDC_BTN_MISSION 9002 +#define IDC_BTN_IMPORT 9010 +#define IDC_BTN_EXPORT 9011 +#define IDC_TXT_FORCE 327 +#define IDC_OFFSET_SETTING 10000 + +#define POS_X(N) ((N) * (((safezoneW / safezoneH) min 1.2) / 40)) +#define POS_Y(N) ((N) * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)) + +#define OFFSETY(var1,var2) format [QGVAR(offsetY$%1$%2), var1, var2] + +#define COLOR_TEXT_DISABLED [1,1,1,0.3] +#define COLOR_BUTTON_ENABLED [1,1,1,1] +#define COLOR_BUTTON_DISABLED [0,0,0,1] +#define COLOR_TEXT_OVERWRITTEN [1,0.3,0.3,1] + +#define CAN_SET_CLIENT_SETTINGS (!isMultiplayer || {!isServer}) // in singleplayer or as client in multiplayer +#define CAN_SET_SERVER_SETTINGS (isMultiplayer && {isServer || serverCommandAvailable "#logout"}) // in multiplayer and host (local server) or admin (dedicated) +#define CAN_SET_MISSION_SETTINGS is3den // duh + +#ifndef DEBUG_MODE_FULL + #define CAN_VIEW_CLIENT_SETTINGS (!isMultiplayer || {!isServer}) // hide for local hosted MP client to not confuse + #define CAN_VIEW_SERVER_SETTINGS isMultiplayer // everyone can peak at those in multiplayer + #define CAN_VIEW_MISSION_SETTINGS (is3den || missionVersion >= 15) // can view those in 3den or 3den missions +#else + #define CAN_VIEW_CLIENT_SETTINGS true + #define CAN_VIEW_SERVER_SETTINGS true + #define CAN_VIEW_MISSION_SETTINGS true +#endif + +#define GET_TEMP_NAMESPACE(source) ([ARR_3(GVAR(clientSettingsTemp),GVAR(serverSettingsTemp),GVAR(missionSettingsTemp))] param [[ARR_3('client','server','mission')] find toLower source]) +#define SET_TEMP_NAMESPACE_VALUE(setting,value,source) GET_TEMP_NAMESPACE(source) setVariable [ARR_2(setting,[ARR_2(value,(GET_TEMP_NAMESPACE(source) getVariable setting) param [1])])] +#define SET_TEMP_NAMESPACE_FORCED(setting,forced,source) GET_TEMP_NAMESPACE(source) setVariable [ARR_2(setting,[ARR_2((GET_TEMP_NAMESPACE(source) getVariable setting) param [0],forced)])] diff --git a/addons/settings/stringtable.xml b/addons/settings/stringtable.xml new file mode 100644 index 000000000..10b7d83d5 --- /dev/null +++ b/addons/settings/stringtable.xml @@ -0,0 +1,69 @@ + + + + Configure Addons + Modifikationen anpassen + Konfiguracja addonów + + + Configure Base + Hauptspiel anpassen + Konfiguracja bazy + + + Client + Lokal + + + Edit your local settings. Red colored settings are overwritten by the server or mission. + Lokale Einstellungen bearbeiten. Rot geschriebene Einstellungen werden vom Server oder der Mission überschrieben. + + + Server + Server + + + Look at the servers settings. 'Forced' settings overwrite the client and mission settings. Log in as admin to change. + Server-Einstellungen ansehen. 'Erzwungene' Einstellungen überschreiben lokale und Missionseinstellungen. Als Admin einloggen, um zu ändern. + + + Mission + Mission + + + Edit the missions settings. 'Forced' settings overwrite the clients settings. + Missionseinstellungen bearbeiten. 'Erzwungene' Einstellungen überschreiben lokale. + + + Force + Erzwingen + + + Check to overwrite this setting for all connected players. + Wählen, um diese Einstellung für alle verbunden Spieler zu überschreiben. + + + Import + Import + + + Import settings from clipboard. + Einstellungen aus Zwischenablage einfügen. + + + Export + Export + + + Export settings to clipboard. + Einstellungen in Zwischenablage speichern. + + + Default + Voreinst. + + + Setting is overwritten. Check 'Server' or 'Mission' tab. + Einstellung ist überschrieben. Überprüfe 'Server' oder 'Mission'-Reiter. + + diff --git a/addons/settings_helper/$PBOPREFIX$ b/addons/settings_helper/$PBOPREFIX$ new file mode 100644 index 000000000..4001f2a4a --- /dev/null +++ b/addons/settings_helper/$PBOPREFIX$ @@ -0,0 +1 @@ +userconfig/ diff --git a/addons/settings_helper/$SCRIPTSFOLDER$ b/addons/settings_helper/$SCRIPTSFOLDER$ new file mode 100644 index 000000000..e69de29bb diff --git a/addons/settings_helper/cba/settings.sqf b/addons/settings_helper/cba/settings.sqf new file mode 100644 index 000000000..e69de29bb diff --git a/addons/settings_helper/config.cpp b/addons/settings_helper/config.cpp new file mode 100644 index 000000000..cfec43b17 --- /dev/null +++ b/addons/settings_helper/config.cpp @@ -0,0 +1,18 @@ +// the purpose of this PBO is to set a default file to the following path: +// userconfig/cba/settings.sqf +// this way we effectively make the file optional, as the loadFile command +// can fall back to this empty default file + +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {}; + version = VERSION; + author[] = {"commy2"}; + authorUrl = "https://github.com/CBATeam/CBA_A3"; + }; +}; diff --git a/addons/settings_helper/script_component.hpp b/addons/settings_helper/script_component.hpp new file mode 100644 index 000000000..254e5c3b1 --- /dev/null +++ b/addons/settings_helper/script_component.hpp @@ -0,0 +1,3 @@ +#define COMPONENT settings_helper +#include "\x\cba\addons\main\script_mod.hpp" +#include "\x\cba\addons\main\script_macros.hpp" diff --git a/tools/build.py b/tools/build.py index 6cb5ebc89..ef9747834 100644 --- a/tools/build.py +++ b/tools/build.py @@ -68,11 +68,17 @@ def main(): print("# Making {} ...".format(p)) + usescriptsfolder = os.path.join(path, "$SCRIPTSFOLDER$") + if os.path.isfile(usescriptsfolder): + pbopath = "-@=userconfig" + else: + pbopath = "-@={}\\{}\\addons\\{}".format(MAINPREFIX,PREFIX.rstrip("_"),p) + try: subprocess.check_output([ "makepbo", "-NUP", - "-@={}\\{}\\addons\\{}".format(MAINPREFIX,PREFIX.rstrip("_"),p), + pbopath, p, "{}{}.pbo".format(PREFIX,p) ], stderr=subprocess.STDOUT)