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/Cfg3DEN.hpp b/addons/settings/Cfg3DEN.hpp new file mode 100644 index 000000000..52fd4f459 --- /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(hash) { + property = QGVAR(hash); + value = 0; + control = "Default"; // blank space. not editable by hand + displayName = ""; + tooltip = ""; + defaultValue = QUOTE(NULL_HASH); + expression = QUOTE(missionNamespace setVariable [ARR_3(QUOTE(QGVAR(hash)),_value,true)]); + wikiType = "[[Array]]"; + }; + }; + }; + }; + }; + }; +}; diff --git a/addons/settings/CfgEventHandlers.hpp b/addons/settings/CfgEventHandlers.hpp new file mode 100644 index 000000000..b19cf6343 --- /dev/null +++ b/addons/settings/CfgEventHandlers.hpp @@ -0,0 +1,27 @@ + +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(if (!IS_LINUX) then {call COMPILE_FILE(XEH_preStart)};); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(if (!IS_LINUX) then {call COMPILE_FILE(XEH_preInit)};); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(if (!IS_LINUX) then {call COMPILE_FILE(XEH_postInit)};); + }; +}; + +class Extended_DisplayLoad_EventHandlers { + class RscDisplayGameOptions { + ADDON = QUOTE(if (IS_LINUX || {isNil 'ADDON'}) then {_this call COMPILE_FILE(gui_initDisplay_disabled)} else {_this call COMPILE_FILE(gui_initDisplay)};); + }; + class Display3DEN { + ADDON = QUOTE(if (!IS_LINUX) then {_this call COMPILE_FILE(init3DEN)};); + }; +}; 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/Display3DEN.hpp b/addons/settings/Display3DEN.hpp new file mode 100644 index 000000000..d692798f6 --- /dev/null +++ b/addons/settings/Display3DEN.hpp @@ -0,0 +1,20 @@ + +class ctrlMenuStrip; + +class Display3DEN { + class Controls { + class MenuStrip: ctrlMenuStrip { + class Items { + class Options { + items[] += {QUOTE(ADDON)}; + }; + class ADDON { + text = CSTRING(shortcut); + action = QUOTE(findDisplay 313 call COMPILE_FILE(openSettingsMenu)); + data = QUOTE(ADDON); + shortcuts[] = {INPUT_CTRL_OFFSET + INPUT_ALT_OFFSET + DIK_S}; + }; + }; + }; + }; +}; diff --git a/addons/settings/XEH_PREP.sqf b/addons/settings/XEH_PREP.sqf new file mode 100644 index 000000000..82b61ac8e --- /dev/null +++ b/addons/settings/XEH_PREP.sqf @@ -0,0 +1,19 @@ + +PREP(init); +PREP(set); +PREP(get); +PREP(check); +PREP(parse); +PREP(import); +PREP(export); +PREP(clear); +PREP(saveTempData); +PREP(isForced); +PREP(isOverwritten); + +PREP(gui_addonChanged); +PREP(gui_sourceChanged); +PREP(gui_configure); +PREP(gui_closeMenu); +PREP(gui_refresh); +PREP(gui_preset); diff --git a/addons/settings/XEH_postInit.sqf b/addons/settings/XEH_postInit.sqf new file mode 100644 index 000000000..031726f61 --- /dev/null +++ b/addons/settings/XEH_postInit.sqf @@ -0,0 +1,48 @@ +#include "script_component.hpp" + +// --- refresh all settings after postInit to guarantee that events are added and settings are recieved from server +{ + if (isNil QGVAR(serverSettings)) then { + diag_log text "[CBA] (settings): No server settings after postInit phase."; + }; + + GVAR(ready) = true; + { + [QGVAR(refreshSetting), _x] call CBA_fnc_localEvent; + } forEach GVAR(allSettings); +} call CBA_fnc_execNextFrame; + +// --- autosave mission and server presets +private _presetsHash = profileNamespace getVariable [QGVAR(presetsHash), NULL_HASH]; +private _autosavedPresets = profileNamespace getVariable [QGVAR(autosavedPresets), [[],[]]]; + +if !(allVariables GVAR(missionSettings) isEqualTo []) then { + private _preset = "mission" call FUNC(export); + private _presetName = format ["Autosave: %1 (%2)", localize LSTRING(ButtonMission), missionName]; + + [_presetsHash, _presetName, _preset] call CBA_fnc_hashSet; + + (_autosavedPresets select 0) pushBackUnique _presetName; + + if (count (_autosavedPresets select 0) > 3) then { + private _presetToRemove = (_autosavedPresets select 0) deleteAt 0; + [_presetsHash, _presetToRemove] call CBA_fnc_hashRem; + }; +}; + +if (serverName != "") then { + private _preset = "server" call FUNC(export); + private _presetName = format ["Autosave: %1 (%2)", localize LSTRING(ButtonServer), serverName]; + + [_presetsHash, _presetName, _preset] call CBA_fnc_hashSet; + + (_autosavedPresets select 1) pushBackUnique _presetName; + + if (count (_autosavedPresets select 1) > 3) then { + private _presetToRemove = (_autosavedPresets select 1) deleteAt 0; + [_presetsHash, _presetToRemove] call CBA_fnc_hashRem; + }; +}; + +profileNamespace setVariable [QGVAR(presetsHash), _presetsHash]; +profileNamespace setVariable [QGVAR(autosavedPresets), _autosavedPresets]; diff --git a/addons/settings/XEH_preInit.sqf b/addons/settings/XEH_preInit.sqf new file mode 100644 index 000000000..3492c2f98 --- /dev/null +++ b/addons/settings/XEH_preInit.sqf @@ -0,0 +1,74 @@ +//#define DEBUG_MODE_FULL +#include "script_component.hpp" + +ADDON = false; + +#include "XEH_PREP.sqf" + +#ifdef DEBUG_MODE_FULL +["Test_Setting_1", "CHECKBOX", ["-test checkbox-", "-tooltip-"], "My Category", true] call cba_settings_fnc_init; +["Test_Setting_2", "LIST", ["-test list-", "-tooltip-"], "My Category", [[1,0], ["enabled","disabled"], 1]] call cba_settings_fnc_init; +["Test_Setting_3", "SLIDER", ["-test slider-", "-tooltip-"], "My Category", [0, 10, 5, 0]] call cba_settings_fnc_init; +["Test_Setting_4", "COLOR", ["-test color-", "-tooltip-"], "My Category", [1,1,0]] call cba_settings_fnc_init; +#endif + +// --- init settings namespaces +#include "initSettings.sqf" + +// --- event to refresh missionNamespace value if setting has changed and call public event as well as execute setting script +[QGVAR(refreshSetting), { + params ["_setting"]; + private _value = _setting call FUNC(get); + + missionNamespace setVariable [_setting, _value]; + + if (isNil QGVAR(ready)) exitWith {}; + + private _script = NAMESPACE_GETVAR(GVAR(defaultSettings),_setting,[]) param [8, {}]; + [_value, _script] call { + private ["_setting", "_value", "_script"]; // prevent these variables from being overwritten + (_this select 0) call (_this select 1); + }; + + ["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_localEvent; + } forEach GVAR(allSettings); +}] call CBA_fnc_addEventHandler; + +// refresh all settings when loading a save game +addMissionEventHandler ["Loaded", { + QGVAR(refreshAllSettings) call CBA_fnc_localEvent; +}]; + +#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..43f1adee3 --- /dev/null +++ b/addons/settings/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.sqf" diff --git a/addons/settings/config.cpp b/addons/settings/config.cpp new file mode 100644 index 000000000..d6f4e5f5a --- /dev/null +++ b/addons/settings/config.cpp @@ -0,0 +1,23 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + author = "$STR_CBA_Author"; + name = CSTRING(component); + url = "$STR_CBA_URL"; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"CBA_common", "A3_UI_F", "3DEN"}; + version = VERSION; + authors[] = {"commy2"}; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgFunctions.hpp" + +#include "Cfg3DEN.hpp" +#include "Display3DEN.hpp" + +#include "gui.hpp" diff --git a/addons/settings/fnc_check.sqf b/addons/settings/fnc_check.sqf new file mode 100644 index 000000000..8e2f6b9ea --- /dev/null +++ b/addons/settings/fnc_check.sqf @@ -0,0 +1,41 @@ +/* ---------------------------------------------------------------------------- +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: + _return - true: Tested value is accepted for setting, false: Wrong value for setting + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_setting", "", [""]], "_value"]; + +if (isNil "_value") exitWith {false}; + +NAMESPACE_GETVAR(GVAR(defaultSettings),_setting,[]) params ["_defaultValue", "", ["_settingType", ""], "_settingData"]; + +switch (toUpper _settingType) do { + case ("CHECKBOX"): { + _value isEqualType false + }; + case ("LIST"): { + _settingData params ["_values"]; + _value in _values + }; + case ("SLIDER"): { + _settingData params ["_min", "_max"]; + _value isEqualType 0 && {_value >= _min} && {_value <= _max} + }; + case ("COLOR"): { + _value isEqualType [] && {count _value == count _defaultValue} && {_value isEqualTypeAll 0} && {{_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..345f43e8f --- /dev/null +++ b/addons/settings/fnc_clear.sqf @@ -0,0 +1,50 @@ +/* ---------------------------------------------------------------------------- +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(hash), NULL_HASH]; + GVAR(clientSettings) call CBA_fnc_deleteNamespace; + GVAR(clientSettings) = [] call CBA_fnc_createNamespace; + }; + case ("server"): { + if (!isServer) exitWith {}; + + profileNamespace setVariable [QGVAR(hash), NULL_HASH]; + GVAR(serverSettings) call CBA_fnc_deleteNamespace; + GVAR(serverSettings) = isMultiplayer call CBA_fnc_createNamespace; + publicVariable QGVAR(serverSettings); + }; + case ("mission"): { + if (!is3DEN) exitWith {}; + + set3DENMissionAttributes [["Scenario", QGVAR(hash), NULL_HASH]]; + GVAR(missionSettings) call CBA_fnc_deleteNamespace; + GVAR(missionSettings) = [] call 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_export.sqf b/addons/settings/fnc_export.sqf new file mode 100644 index 000000000..d2453b3a8 --- /dev/null +++ b/addons/settings/fnc_export.sqf @@ -0,0 +1,47 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_export + +Description: + Export all setting info to string. + +Parameters: + _source - Can be "client", "server" or "mission" (optional, default: "client") + +Returns: + Formatted setting info. + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +#define NEWLINE toString [10] +#define KEYWORD_FORCE "force" + +params [["_source", "client", [""]]]; + +private _info = ""; + +{ + private _setting = _x; + private _value = GET_TEMP_NAMESPACE_VALUE(_setting,_source); + + if (isNil "_value") then { + _value = [_setting, _source] call FUNC(get); + }; + + private _forced = GET_TEMP_NAMESPACE_FORCED(_setting,_source); + + if (isNil "_forced") then { + _forced = [_setting, _source] call FUNC(isForced); + }; + + // not displayed for client settings - assume it's not forced + if (_source == "client") then { + _forced = false; + }; + + _info = _info + ((["", KEYWORD_FORCE + " "] select _forced) + _setting + " = " + format ["%1", _value] + ";" + NEWLINE); +} forEach GVAR(allSettings); + +_info diff --git a/addons/settings/fnc_get.sqf b/addons/settings/fnc_get.sqf new file mode 100644 index 000000000..d646c2acb --- /dev/null +++ b/addons/settings/fnc_get.sqf @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- +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"): { + GET_VALUE(clientSettings,_setting); + }; + case ("server"): { + GET_VALUE(serverSettings,_setting); + }; + case ("mission"): { + GET_VALUE(missionSettings,_setting); + }; + case ("default"): { + GET_VALUE(defaultSettings,_setting); + }; + case ("forced"): { + private _value = [_setting, "client"] call FUNC(get); + + if ([_setting, "mission"] call FUNC(isForced)) then { + _value = [_setting, "mission"] call FUNC(get); + }; + + if ([_setting, "server"] call FUNC(isForced)) then { + _value = [_setting, "server"] call FUNC(get); + }; + + 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..3525fe836 --- /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 = _display 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 = _display getVariable _x; + private _isSelected = _source == _selectedSource && {_addon == _selectedAddon}; + + _ctrlOptionsGroup ctrlEnable _isSelected; + _ctrlOptionsGroup ctrlShow _isSelected; +} forEach (_display 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..5bf8ca4be --- /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 CBA_fnc_deleteNamespace; +GVAR(clientSettingsTemp) = nil; + +GVAR(serverSettingsTemp) call CBA_fnc_deleteNamespace; +GVAR(serverSettingsTemp) = nil; + +GVAR(missionSettingsTemp) call 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..ddc8a30fe --- /dev/null +++ b/addons/settings/fnc_gui_configure.sqf @@ -0,0 +1,121 @@ +#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; +private _ctrlButtonSave = _display displayCtrl IDC_BTN_SAVE; +private _ctrlButtonLoad = _display displayCtrl IDC_BTN_LOAD; + +// 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; + _ctrlButtonSave ctrlEnable true; + _ctrlButtonSave ctrlShow true; + _ctrlButtonLoad ctrlEnable true; + _ctrlButtonLoad 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; + _ctrlButtonSave ctrlEnable false; + _ctrlButtonSave ctrlShow false; + _ctrlButtonLoad ctrlEnable false; + _ctrlButtonLoad ctrlShow false; + + //--- change button text + _ctrlToggleButton ctrlSetText localize LSTRING(configureAddons); +}; diff --git a/addons/settings/fnc_gui_preset.sqf b/addons/settings/fnc_gui_preset.sqf new file mode 100644 index 000000000..8b1f348ba --- /dev/null +++ b/addons/settings/fnc_gui_preset.sqf @@ -0,0 +1,111 @@ +#include "script_component.hpp" + +// get button +params ["_parentDisplay", "_mode"]; + +_display = _parentDisplay createDisplay QGVAR(presets); + +private _ctrlPresetsGroup = _display displayCtrl IDC_PRESETS_GROUP; +private _ctrlTitle = _display displayCtrl IDC_PRESETS_TITLE; +private _ctrlName = _display displayCtrl IDC_PRESETS_NAME; +private _ctrlEdit = _display displayCtrl IDC_PRESETS_EDIT; +private _ctrlValue = _display displayCtrl IDC_PRESETS_VALUE; +private _ctrlOK = _display displayCtrl IDC_PRESETS_OK; +private _ctrlCancel = _display displayCtrl IDC_PRESETS_CANCEL; +private _ctrlDelete = _display displayCtrl IDC_PRESETS_DELETE; + +if (_mode == "save") then { + _ctrlTitle ctrlSetText localize "STR_DISP_INT_SAVE"; + + // --- generate default name + _ctrlEdit ctrlSetText format ["New: %1", + localize ([ + LSTRING(ButtonClient), LSTRING(ButtonServer), LSTRING(ButtonMission) + ] param [[ + "client", "server", "mission" + ] find (uiNamespace getVariable QGVAR(source))]) + ]; + + _ctrlValue ctrlAddEventHandler ["LBSelChanged", { + params ["_control", "_index"]; + private _display = ctrlParent _control; + + private _ctrlEdit = _display displayCtrl IDC_PRESETS_EDIT; + _ctrlEdit ctrlSetText (_control lbText _index); + }]; + + ctrlSetFocus _ctrlEdit; +} else { + _ctrlTitle ctrlSetText localize "STR_DISP_INT_LOAD"; + + // --- hide edit box in "load" mode + _ctrlName ctrlEnable false; + _ctrlName ctrlShow false; + + _ctrlEdit ctrlEnable false; + _ctrlEdit ctrlShow false; +}; + +// --- fill listbox with profile stored presets +private _presetsHash = profileNamespace getVariable [QGVAR(presetsHash), NULL_HASH]; + +[_presetsHash, { + private _index = _ctrlValue lbAdd _key; + _ctrlValue lbSetData [_index, str _index]; + _ctrlValue setVariable [str _index, _value]; +}] call CBA_fnc_hashEachPair; + +// --- scripted buttons +if (_mode == "save") then { + _ctrlOK ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + private _display = ctrlParent _control; + + private _ctrlEdit = _display displayCtrl IDC_PRESETS_EDIT; + private _presetName = ctrlText _ctrlEdit; + + private _preset = [uiNamespace getVariable QGVAR(source)] call FUNC(export); + private _presetsHash = profileNamespace getVariable [QGVAR(presetsHash), NULL_HASH]; + + [_presetsHash, _presetName, _preset] call CBA_fnc_hashSet; + profileNamespace setVariable [QGVAR(presetsHash), _presetsHash]; + + _display closeDisplay 1; + }]; +} else { + _ctrlOK ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + private _display = ctrlParent _control; + + private _ctrlValue = _display displayCtrl IDC_PRESETS_VALUE; + private _index = lbCurSel _ctrlValue; + private _preset = _ctrlValue getVariable [_ctrlValue lbData _index, ""]; + + [_preset, uiNamespace getVariable QGVAR(source)] call FUNC(import); + + _display closeDisplay 1; + }]; +}; + +_ctrlCancel ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + private _display = ctrlParent _control; + + _display closeDisplay 2; +}]; + +_ctrlDelete ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + private _display = ctrlParent _control; + + private _ctrlValue = _display displayCtrl IDC_PRESETS_VALUE; + private _index = lbCurSel _ctrlValue; + private _presetName = _ctrlValue lbText _index; + + _ctrlValue lbDelete _index; + + private _presetsHash = profileNamespace getVariable [QGVAR(presetsHash), NULL_HASH]; + + [_presetsHash, _presetName] call CBA_fnc_hashRem; + profileNamespace setVariable [QGVAR(presetsHash), _presetsHash]; +}]; diff --git a/addons/settings/fnc_gui_refresh.sqf b/addons/settings/fnc_gui_refresh.sqf new file mode 100644 index 000000000..e96b6f7cf --- /dev/null +++ b/addons/settings/fnc_gui_refresh.sqf @@ -0,0 +1,77 @@ +#include "script_component.hpp" + +private _display = uiNamespace getVariable [QGVAR(display), displayNull]; +private _ctrlOptionsGroup = ((_display getVariable [QGVAR(controls), []]) select {ctrlShown _x}) param [0, controlNull]; +private _contols = _ctrlOptionsGroup getVariable [QGVAR(controls), []]; + +{ + private _linkedControls = _x getVariable QGVAR(linkedControls); + (_x getVariable QGVAR(data)) params ["_setting", "_source"]; + (GVAR(defaultSettings) getVariable _setting) params ["_defaultValue", "", "_settingType", "_settingData"]; + + private _value = GET_TEMP_NAMESPACE_VALUE(_setting,_source); + + // --- reset settings controls to current state + if (!isNil "_value") then { + switch (toUpper _settingType) do { + case ("CHECKBOX"): { + _linkedControls params ["_ctrlSetting"]; + + _ctrlSetting cbSetChecked _value; + }; + case ("LIST"): { + _settingData params ["_values"]; + _linkedControls params ["_ctrlSetting"]; + + _ctrlSetting lbSetCurSel (_values find _value); + }; + case ("SLIDER"): { + _settingData params ["", "", "_trailingDecimals"]; + _linkedControls params ["_ctrlSetting", "_ctrlSettingEdit"]; + + _ctrlSetting sliderSetPosition _value; + _ctrlSettingEdit ctrlSetText ([_value, 1, _trailingDecimals] call CBA_fnc_formatNumber); + }; + case ("COLOR"): { + _linkedControls params ["_ctrlSettingPreview", "_settingControls"]; + + _value 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 _valueX = _value select _forEachIndex; + + _ctrlSetting sliderSetPosition _valueX; + _ctrlSettingEdit ctrlSetText ([_valueX, 1, 2] call CBA_fnc_formatNumber); + } forEach _settingControls; + }; + default {}; + }; + }; + + private _forced = GET_TEMP_NAMESPACE_FORCED(_setting,_source); + + // --- reset force buttons to current state + if (!isNil "_forced") then { + switch (toUpper _settingType) do { + case ("CHECKBOX"); + case ("LIST"): { + private _ctrlSettingForce = _linkedControls param [2, controlNull]; + _ctrlSettingForce cbSetChecked _forced; + }; + case ("SLIDER"); + case ("COLOR"): { + private _ctrlSettingForce = _linkedControls param [3, controlNull]; + _ctrlSettingForce cbSetChecked _forced; + }; + default {}; + }; + }; +} forEach _contols; diff --git a/addons/settings/fnc_gui_sourceChanged.sqf b/addons/settings/fnc_gui_sourceChanged.sqf new file mode 100644 index 000000000..04af776d7 --- /dev/null +++ b/addons/settings/fnc_gui_sourceChanged.sqf @@ -0,0 +1,52 @@ +#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 = _display getVariable _x; + private _isSelected = _source == _selectedSource && {_addon == _selectedAddon}; + + _ctrlOptionsGroup ctrlEnable _isSelected; + _ctrlOptionsGroup ctrlShow _isSelected; +} forEach (_display 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"); + +// enable / disable IMPORT and LOAD buttons +private _ctrlButtonImport = _display displayCtrl IDC_BTN_IMPORT; +private _ctrlButtonLoad = _display displayCtrl IDC_BTN_LOAD; + +private _enabled = switch (_selectedSource) do { + case ("client"): { + CAN_SET_CLIENT_SETTINGS + }; + case ("server"): { + CAN_SET_SERVER_SETTINGS + }; + case ("mission"): { + CAN_SET_MISSION_SETTINGS + }; +}; + +_ctrlButtonImport ctrlEnable _enabled; +_ctrlButtonLoad ctrlEnable _enabled; diff --git a/addons/settings/fnc_import.sqf b/addons/settings/fnc_import.sqf new file mode 100644 index 000000000..173e3130c --- /dev/null +++ b/addons/settings/fnc_import.sqf @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_import + +Description: + Import all setting info from string. + +Parameters: + _info - Formated settings info, (from CBA_settings_fnc_export), (optional, default: clipboard) + _source - Can be "client", "server" or "mission" (optional, default: "client") + +Returns: + None + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +params [["_info", "", [""]], ["_source", "client", [""]]]; + +_info = _info call FUNC(parse); + +{ + _x params ["_setting", "_value", "_force"]; + + SET_TEMP_NAMESPACE_VALUE(_setting,_value,_source); + SET_TEMP_NAMESPACE_FORCED(_setting,_force,_source); +} forEach _info; + +call FUNC(gui_refresh); diff --git a/addons/settings/fnc_init.sqf b/addons/settings/fnc_init.sqf new file mode 100644 index 000000000..701fc93e0 --- /dev/null +++ b/addons/settings/fnc_init.sqf @@ -0,0 +1,167 @@ +/* ---------------------------------------------------------------------------- +Internal Function: CBA_settings_fnc_init + +Description: + Creates a new setting for that session. + +Parameters: + _setting - Unique setting name. Matches resulting variable name + _settingType - Type of setting. Can be "CHECKBOX", "LIST", "SLIDER" or "COLOR" + _title - Display name or display name + tooltip (optional, default: same as setting name) + _category - Category for the settings menu + _valueInfo - Extra properties of the setting depending of _settingType. See examples below + _isGlobal - true: all clients share the same state of the setting (optional, default: false) + _script - Script to execute when setting is changed or forced. (optional) + +Returns: + _return - Error code + 0: Success, no error + 1: Empty setting name + 2: Empty menu category + 3: Wrong setting type (couldn't find correct default value) + +Examples: + (begin example) + // CHECKBOX --- extra argument: default value + ["Test_Setting_1", "CHECKBOX", ["-test checkbox-", "-tooltip-"], "My Category", true] call cba_settings_fnc_init; + + // LIST --- extra arguments: [_values, _valueTitles, _defaultIndex] + ["Test_Setting_2", "LIST", ["-test list-", "-tooltip-"], "My Category", [[1,0], ["enabled","disabled"], 1]] call cba_settings_fnc_init; + + // SLIDER --- extra arguments: [_min, _max, _default, _trailingDecimals] + ["Test_Setting_3", "SLIDER", ["-test slider-", "-tooltip-"], "My Category", [0, 10, 5, 0]] call cba_settings_fnc_init; + + // COLOR PICKER --- extra argument: _color + ["Test_Setting_4", "COLOR", ["-test color-", "-tooltip-"], "My Category", [1,1,0]] call cba_settings_fnc_init; + (end) + +Author: + commy2 +---------------------------------------------------------------------------- */ +#include "script_component.hpp" + +// prevent race conditions. function could be called from scheduled env. +if (canSuspend) exitWith { + [FUNC(init), _this] call CBA_fnc_directCall; +}; + +// --- init settings system, makes this function useable in preInit without having to add "CBA_settings" to requiredAddons +#include "initSettings.sqf" + +params [ + ["_setting", "", [""]], + ["_settingType", "", [""]], + ["_title", [], ["", []]], + ["_category", "", [""]], + ["_valueInfo", []], + ["_isGlobal", false, [false]], + ["_script", {}, [{}]] +]; + +if (_setting isEqualTo "") exitWith {1}; +if (_category isEqualTo "") exitWith {2}; + +// --- setting title and tooltip +_title params [["_displayName", "", [""]], ["_tooltip", "", [""]]]; + +if (_displayName isEqualTo "") then { + _displayName = _setting; +}; + +// --- setting possible values and default ("data") +private "_defaultValue"; +private _settingData = []; + +switch (toUpper _settingType) do { + case ("CHECKBOX"): { + _defaultValue = _valueInfo param [0, false, [false]]; // don't use params - we want these variables to be private to the main scope + }; + case ("LIST"): { + _valueInfo params [["_values", [], [[]]], ["_labels", [], [[]]], ["_defaultIndex", 0, [0]]]; + + if (_values isEqualTo []) then { + { + _values pushBack _forEachIndex; + } forEach _labels; + }; + + _labels resize count _values; + + { + if (isNil "_x") then { + _x = _values select _forEachIndex; + }; + + if !(_x isEqualType "") then { + _x = str _x; + }; + + _labels set [_forEachIndex, _x]; + } forEach _labels; + + _defaultValue = _values param [_defaultIndex]; + _settingData append [_values, _labels]; + }; + case ("SLIDER"): { + _valueInfo params [["_min", 0, [0]], ["_max", 1, [0]], ["_default", 0, [0]], ["_trailingDecimals", 2, [0]]]; + + _defaultValue = _default; + _settingData append [_min, _max, _trailingDecimals]; + }; + case ("COLOR"): { + _defaultValue = [_valueInfo] param [0, [1,1,1], [[]], [3,4]]; + }; + default {/* _defaultValue undefined, exit below */}; +}; + +if (isNil "_defaultValue") exitWith {3}; + +// --- add setting info to settings namespace +GVAR(defaultSettings) setVariable [_setting, [_defaultValue, _setting, _settingType, _settingData, _category, _displayName, _tooltip, _isGlobal, _script]]; +GVAR(allSettings) pushBackUnique _setting; + +// --- read previous setting values from profile +private _settingsHash = profileNamespace getVariable [QGVAR(hash), NULL_HASH]; +private _settingInfo = [_settingsHash, toLower _setting] call CBA_fnc_hashGet; + +if (!isNil "_settingInfo") then { + _settingInfo params ["_value", "_forced"]; + + 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]; + }; +}; + +// --- read previous setting values from mission +_settingsHash = missionNamespace getVariable [QGVAR(hash), "Scenario" get3DENMissionAttribute QGVAR(hash)]; + +if (isNil "_settingsHash") then { + _settingsHash = NULL_HASH; +}; + +_settingInfo = [_settingsHash, toLower _setting] call CBA_fnc_hashGet; + +if (!isNil "_settingInfo") then { + _settingInfo params ["_value", "_forced"]; + + 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; +}; + +0 diff --git a/addons/settings/fnc_isForced.sqf b/addons/settings/fnc_isForced.sqf new file mode 100644 index 000000000..bfa6bf0cd --- /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"): { + GET_FORCED(clientSettings,_setting); + }; + case ("server"): { + GET_FORCED(serverSettings,_setting); + }; + case ("mission"): { + GET_FORCED(missionSettings,_setting); + }; + 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..9a2d4fd62 --- /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 CBA_fnc_trim; + _value = (_statement select [(_statement find "=") + 1]) call CBA_fnc_trim; + + 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..6ef9511fa --- /dev/null +++ b/addons/settings/fnc_set.sqf @@ -0,0 +1,104 @@ +/* ---------------------------------------------------------------------------- +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: + _return - Error code + 0: succes + 1: invalid value for setting + 2: new setting and forced state are the same as the previous ones + 10: invalid source + 11: server source, but in SP + 12: server source, but no access + 13: mission source, but not in 3DEN editor + +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]; + 1 +}; + +private _currentValue = [_setting, _source] call FUNC(get); +private _currentForced = [_setting, _source] call FUNC(isForced); + +if (isNil "_forced") then { + _forced = _currentForced; +}; + +if (!isNil "_currentValue" && {_value isEqualTo _currentValue} && {_forced isEqualTo _currentForced}) exitWith {2}; + +private _return = 0; + +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]]; + + private _settingsHash = profileNamespace getVariable [QGVAR(hash), NULL_HASH]; + [_settingsHash, toLower _setting, [_value, _forced]] call CBA_fnc_hashSet; + profileNamespace setVariable [QGVAR(hash), _settingsHash]; + + [QGVAR(refreshSetting), _setting] call CBA_fnc_localEvent; + }; + case ("server"): { + if (!isMultiplayer) exitWith { + _return = 11; + }; + + if (isServer) then { + GVAR(clientSettings) setVariable [_setting, [_value, _forced]]; + GVAR(serverSettings) setVariable [_setting, [_value, _forced], true]; + + private _settingsHash = profileNamespace getVariable [QGVAR(hash), NULL_HASH]; + [_settingsHash, toLower _setting, [_value, _forced]] call CBA_fnc_hashSet; + profileNamespace setVariable [QGVAR(hash), _settingsHash]; + + [QGVAR(refreshSetting), _setting] call CBA_fnc_globalEvent; + } else { + if (serverCommandAvailable "#logout") then { + [QGVAR(setSettingServer), [_setting, _value, _forced]] call CBA_fnc_serverEvent; + } else { + _return = 12; + }; + }; + }; + case ("mission"): { + if (!is3DEN) exitWith { + _return = 13; + }; + + GVAR(missionSettings) setVariable [_setting, [_value, _forced]]; + + private _settingsHash = "Scenario" get3DENMissionAttribute QGVAR(hash); + [_settingsHash, toLower _setting, [_value, _forced]] call CBA_fnc_hashSet; + set3DENMissionAttributes [["Scenario", QGVAR(hash), _settingsHash]]; + + [QGVAR(refreshSetting), _setting] call CBA_fnc_localEvent; + }; + default { + _return = 10; + }; +}; + +_return diff --git a/addons/settings/gui.hpp b/addons/settings/gui.hpp new file mode 100644 index 000000000..7e24986e4 --- /dev/null +++ b/addons/settings/gui.hpp @@ -0,0 +1,261 @@ + +class RscControlsGroup { + class VScrollbar; + class HScrollbar; +}; + +class RscTitle; +class RscText; +class CBA_Rsc_SettingText: RscText { + style = 0x01; +}; + +class RscEdit; +class RscCombo; +class RscListBox; +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 = POS_W(0.5); + y = POS_H(3.5); + w = POS_W(35); + h = POS_H(13.8); + lineHeight = POS_H(1); + + 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 = POS_H(12); + x = POS_W(4.5); + y = POS_H(1); + w = POS_W(21); + h = POS_H(1); +}; + +class RscDisplayGameOptions { + class controls { + class CBA_ButtonConfigureAddons: RscButtonMenu { + idc = IDC_BTN_CONFIGURE_ADDONS; + text = CSTRING(configureAddons); + x = POS_X(20.15); + y = POS_Y(23); + w = POS_W(12.5); + h = POS_H(1); + }; + + class CBA_ButtonClient: RscButtonMenu { + idc = IDC_BTN_CLIENT; + text = CSTRING(ButtonClient); + tooltip = CSTRING(ButtonClient_tooltip); + x = POS_X(1); + y = POS_Y(2.1); + w = POS_W(8); + h = POS_H(1); + }; + + class CBA_ButtonServer: CBA_ButtonClient { + idc = IDC_BTN_SERVER; + text = CSTRING(ButtonServer); + tooltip = CSTRING(ButtonServer_tooltip); + x = POS_X(9); + }; + + class CBA_ButtonMission: CBA_ButtonClient { + idc = IDC_BTN_MISSION; + text = CSTRING(ButtonMission); + tooltip = CSTRING(ButtonMission_tooltip); + x = POS_X(17); + }; + + class CBA_AddonsGroup: RscControlsGroup { + class VScrollbar: VScrollbar { + width = 0; + }; + class HScrollbar: HScrollbar { + height = 0; + }; + idc = IDC_ADDONS_GROUP; + enableDisplay = 0; + x = POS_X(1); + y = POS_Y(3.1); + w = POS_W(38); + h = POS_H(17.3); + + class controls { + class CBA_AddonsEmptyBackground: RscText { + idc = -1; + type = 0x00; + text = ""; + colorBackground[] = {0,0,0,0.4}; + x = POS_W(0.5); + y = POS_H(3.5); + w = POS_W(35); + h = POS_H(13.8); + }; + class CBA_AddonsCA_ControlsPageText: RscText { + style = 0x01; + idc = 2002; + text = "Addon:"; + x = POS_W(0.5); + y = POS_H(1); + w = POS_W(4); + h = POS_H(1); + sizeEx = POS_H(1); + }; + class CBA_ForceSettingText: RscText { + style = 0x01; + idc = IDC_TXT_FORCE; + text = ""; + tooltip = CSTRING(force_tooltip); + x = POS_W(25); + y = POS_H(2.5); + w = POS_W(10); + h = POS_H(1); + }; + }; + }; + }; +}; + +class CBA_ButtonConfigureSettings_base: RscButtonMenu { + onButtonClick = QUOTE(ctrlParent (_this select 0) call COMPILE_FILE(openSettingsMenu)); + idc = IDC_BTN_SETTINGS; + text = CSTRING(configureAddons); + x = POS_X(11.1); + y = POS_Y(23); + w = POS_W(10); + h = POS_H(1); +}; + +class RscDisplayMainMap; +class RscDisplayGetReady: RscDisplayMainMap { + class controls { + class CBA_ButtonConfigureSettings: CBA_ButtonConfigureSettings_base {}; + }; +}; + +class RscDisplayServerGetReady: RscDisplayGetReady { + class controls { + class CBA_ButtonConfigureSettings: CBA_ButtonConfigureSettings_base {}; + }; +}; + +class RscDisplayClientGetReady: RscDisplayGetReady { + class controls { + class CBA_ButtonConfigureSettings: CBA_ButtonConfigureSettings_base {}; + }; +}; + +class GVAR(presets) { + idd = -1; + movingEnable = 1; + enableSimulation = 0; + + class controls { + class CBA_Presets: RscControlsGroup { + idc = IDC_PRESETS_GROUP; + x = POS_X_CENTERED(10); + y = POS_Y_CENTERED(0.9); + w = POS_W(20); + h = POS_H(22.2); + + class controls { + class CBA_Title: RscTitle { + style = 0; + colorBackground[] = {"(profilenamespace getvariable ['GUI_BCG_RGB_R',0.77])","(profilenamespace getvariable ['GUI_BCG_RGB_G',0.51])","(profilenamespace getvariable ['GUI_BCG_RGB_B',0.08])","(profilenamespace getvariable ['GUI_BCG_RGB_A',0.8])"}; + idc = IDC_PRESETS_TITLE; + text = ""; + x = POS_W(0); + y = POS_H(0); + w = POS_W(20); + h = POS_H(1); + }; + class CBA_Background: RscText { + idc = -1; + colorBackground[] = {0,0,0,0.8}; + x = POS_W(0); + y = POS_H(1.1); + w = POS_W(20); + h = POS_H(20); + }; + class CBA_TextName: RscText { + style = 1; + idc = IDC_PRESETS_NAME; + text = "$STR_DISP_INTEL_NAME"; + x = POS_W(0.5); + y = POS_H(19.6); + w = POS_W(5.5); + h = POS_H(1); + sizeEx = POS_H(0.8); + }; + class CBA_EditName: RscEdit { + idc = IDC_PRESETS_EDIT; + x = POS_W(6); + y = POS_H(19.6); + w = POS_W(13.5); + h = POS_H(1); + sizeEx = POS_H(0.8); + }; + class CBA_ValueName: RscListBox { + idc = IDC_PRESETS_VALUE; + colorBackground[] = {1,1,1,0.2}; + x = POS_W(0.5); + y = POS_H(1.6); + w = POS_W(19); + h = POS_H(17.5); + sizeEx = POS_H(0.8); + }; + class CBA_ButtonOK: RscButtonMenu { + idc = IDC_PRESETS_OK; + text = "$STR_DISP_OK"; + x = POS_W(15); + y = POS_H(21.2); + w = POS_W(5); + h = POS_H(1); + }; + class CBA_ButtonCancel: RscButtonMenu { + idc = IDC_PRESETS_CANCEL; + text = "$STR_DISP_CANCEL"; + x = POS_W(0); + y = POS_H(21.2); + w = POS_W(5); + h = POS_H(1); + }; + class CBA_ButtonDelete: RscButtonMenu { + idc = IDC_PRESETS_DELETE; + text = "$STR_DISP_DELETE"; + x = POS_W(9.9); + y = POS_H(21.2); + w = POS_W(5); + h = POS_H(1); + }; + }; + }; + }; +}; diff --git a/addons/settings/gui_createMenu.sqf b/addons/settings/gui_createMenu.sqf new file mode 100644 index 000000000..001588ffa --- /dev/null +++ b/addons/settings/gui_createMenu.sqf @@ -0,0 +1,108 @@ +// inline function, don't include script_component.hpp + +private _lists = []; +_display setVariable [QGVAR(lists), _lists]; +_display setVariable [QGVAR(controls), []]; + +{ + (GVAR(defaultSettings) getVariable _x) params ["_defaultValue", "_setting", "_settingType", "_settingData", "_category", "_displayName", "_tooltip", "_isGlobal"]; + + if (isLocalized _category) then { + _category = localize _category; + }; + + if (isLocalized _displayName) then { + _displayName = localize _displayName; + }; + + if (isLocalized _tooltip) then { + _tooltip = localize _tooltip; + }; + + _categories pushBackUnique _category; + + { + private _source = toLower _x; + private _currentValue = [_setting, _source] call FUNC(get); + + // ----- create or retrieve options "list" controls group + private _list = [QGVAR(list), _category, _source] joinString "$"; + + private _ctrlOptionsGroup = controlNull; + + if !(_list in _lists) then { + _ctrlOptionsGroup = _display ctrlCreate [QGVAR(OptionsGroup), -1, _display displayCtrl IDC_ADDONS_GROUP]; + _ctrlOptionsGroup ctrlEnable false; + _ctrlOptionsGroup ctrlShow false; + + (_display getVariable QGVAR(controls)) pushBack _ctrlOptionsGroup; + _ctrlOptionsGroup setVariable [QGVAR(controls), []]; + _ctrlOptionsGroup setVariable [QGVAR(offsetY), MENU_OFFSET_INITIAL]; + + _lists pushBack _list; + _display setVariable [_list, _ctrlOptionsGroup]; + } else { + _ctrlOptionsGroup = _display getVariable _list; + }; + + private _offsetY = _ctrlOptionsGroup getVariable QGVAR(offsetY); + + // ----- create setting name text + private _ctrlSettingName = _display ctrlCreate ["CBA_Rsc_SettingText", -1, _ctrlOptionsGroup]; + + _ctrlSettingName ctrlSetText format ["%1:", _displayName]; + _ctrlSettingName ctrlSetTooltip _tooltip; + _ctrlSettingName ctrlSetPosition [ + POS_W(1), + POS_H(_offsetY), + POS_W(15), + POS_H(1) + ]; + _ctrlSettingName ctrlCommit 0; + + // ----- check if setting can be altered + private _enabled = switch (_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 _contols = _ctrlOptionsGroup getVariable QGVAR(controls); + private _linkedControls = []; + + switch (toUpper _settingType) do { + case ("CHECKBOX"): { + #include "gui_createMenu_checkbox.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" + }; + + _ctrlOptionsGroup setVariable [QGVAR(offsetY), _offsetY + MENU_OFFSET_SPACING]; + } forEach ["client", "server", "mission"]; +} forEach GVAR(allSettings); diff --git a/addons/settings/gui_createMenu_checkbox.sqf b/addons/settings/gui_createMenu_checkbox.sqf new file mode 100644 index 000000000..f2745f8da --- /dev/null +++ b/addons/settings/gui_createMenu_checkbox.sqf @@ -0,0 +1,39 @@ +// inline function, don't include script_component.hpp + +private _ctrlSetting = _display ctrlCreate ["RscCheckBox", count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; +_contols pushBack _ctrlSetting; + +_ctrlSetting ctrlSetPosition [ + POS_W(16), + POS_H(_offsetY), + POS_W(1), + POS_H(1) +]; +_ctrlSetting ctrlCommit 0; +_ctrlSetting cbSetChecked _currentValue; + +private _data = [_setting, _source]; + +_ctrlSetting setVariable [QGVAR(linkedControls), _linkedControls]; +_ctrlSetting setVariable [QGVAR(data), _data]; + +_ctrlSetting ctrlAddEventHandler ["CheckedChanged", { + params ["_control", "_state"]; + + (_control getVariable QGVAR(data)) params ["_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_createMenu_color.sqf b/addons/settings/gui_createMenu_color.sqf new file mode 100644 index 000000000..84bf8511e --- /dev/null +++ b/addons/settings/gui_createMenu_color.sqf @@ -0,0 +1,133 @@ +// inline function, don't include script_component.hpp + +private _ctrlSettingPreview = _display ctrlCreate ["RscText", count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; +_contols pushBack _ctrlSettingPreview; + +_ctrlSettingPreview ctrlSetPosition [ + POS_W(9.5), + POS_H(_offsetY + MENU_OFFSET_COLOR), + POS_W(6), + POS_H(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; + +private _data = [_setting, _source, _currentValue, _color]; + +_ctrlSettingPreview setVariable [QGVAR(linkedControls), _linkedControls]; +_ctrlSettingPreview setVariable [QGVAR(data), _data]; + +_linkedControls append [_ctrlSettingPreview, []]; + +for "_index" from 0 to (((count _defaultValue max 3) min 4) - 1) do { + private _ctrlSetting = _display ctrlCreate [SLIDER_TYPES param [_index, "RscXSliderH"], count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + _contols pushBack _ctrlSetting; + + _ctrlSetting ctrlSetPosition [ + POS_W(16), + POS_H(_offsetY), + POS_W(8), + POS_H(1) + ]; + _ctrlSetting ctrlCommit 0; + + _ctrlSetting sliderSetRange [0, 1]; + _ctrlSetting sliderSetPosition (_currentValue param [_index, 0]); + + _ctrlSetting setVariable [QGVAR(linkedControls), _linkedControls]; + _ctrlSetting setVariable [QGVAR(data), _data]; + _ctrlSetting setVariable [QGVAR(index), _index]; + + _ctrlSetting ctrlAddEventHandler ["SliderPosChanged", { + params ["_control", "_value"]; + + (_control getVariable QGVAR(data)) params ["_setting", "_source", "_currentValue", "_color"]; + private _index = _control getVariable QGVAR(index); + + (_control getVariable QGVAR(linkedControls)) params ["_ctrlSettingPreview", "_linkedControls"]; + private _linkedControl = _linkedControls select _index select 1; + _linkedControl ctrlSetText ([_value, 1, 2] call 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 _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; + _contols pushBack _ctrlSettingEdit; + + _ctrlSettingEdit ctrlSetPosition [ + POS_W(24), + POS_H(_offsetY), + POS_W(2), + POS_H(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 CBA_fnc_formatNumber); + + _ctrlSettingEdit setVariable [QGVAR(linkedControls), _linkedControls]; + _ctrlSettingEdit setVariable [QGVAR(data), _data]; + _ctrlSettingEdit setVariable [QGVAR(index), _index]; + + _ctrlSettingEdit ctrlAddEventHandler ["KeyUp", { + params ["_control"]; + + private _value = parseNumber ctrlText _control; + + (_control getVariable QGVAR(data)) params ["_setting", "_source", "_currentValue", "_color"]; + private _index = _control getVariable QGVAR(index); + + (_control getVariable QGVAR(linkedControls)) params ["_ctrlSettingPreview", "_linkedControls"]; + + private _linkedControl = _linkedControls 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 _index = _control getVariable QGVAR(index); + + (_control getVariable QGVAR(linkedControls)) params ["", "_linkedControls"]; + private _linkedControl = _linkedControls select _index select 0; + + private _value = sliderPosition _linkedControl; + + _control ctrlSetText ([_value, 1, 2] call 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 + MENU_OFFSET_COLOR; +}; + +_offsetY = _offsetY + MENU_OFFSET_COLOR_NEG; diff --git a/addons/settings/gui_createMenu_default.sqf b/addons/settings/gui_createMenu_default.sqf new file mode 100644 index 000000000..e45f5014b --- /dev/null +++ b/addons/settings/gui_createMenu_default.sqf @@ -0,0 +1,76 @@ +// inline function, don't include script_component.hpp + +private _ctrlSettingDefault = _display ctrlCreate ["RscButtonMenu", count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; +_contols pushBack _ctrlSettingDefault; + +_ctrlSettingDefault ctrlSetPosition [ + POS_W(27), + POS_H(_ctrlOptionsGroup getVariable QGVAR(offsetY)), + POS_W(5), + POS_H(1) +]; +_ctrlSettingDefault ctrlCommit 0; +_ctrlSettingDefault ctrlSetText localize LSTRING(Default); + +private _data = [_setting, _source, _defaultValue, _settingType, _settingData]; + +_ctrlSettingDefault setVariable [QGVAR(linkedControls), _linkedControls]; +_ctrlSettingDefault setVariable [QGVAR(data), _data]; + +_ctrlSettingDefault ctrlAddEventHandler ["ButtonClick", { + params ["_control"]; + + (_control getVariable QGVAR(data)) params ["_setting", "_source", "_defaultValue", "_settingType", "_settingData"]; + SET_TEMP_NAMESPACE_VALUE(_setting,_defaultValue,_source); + + private _linkedControls = _control getVariable QGVAR(linkedControls); + + // reset buttons to default state + switch (toUpper _settingType) do { + case ("CHECKBOX"): { + _linkedControls params ["_ctrlSetting"]; + + _ctrlSetting cbSetChecked _defaultValue; + }; + case ("LIST"): { + _settingData params ["_values"]; + _linkedControls params ["_ctrlSetting"]; + + _ctrlSetting lbSetCurSel (_values find _defaultValue); + }; + case ("SLIDER"): { + _settingData params ["", "", "_trailingDecimals"]; + _linkedControls params ["_ctrlSetting", "_ctrlSettingEdit"]; + + _ctrlSetting sliderSetPosition _defaultValue; + _ctrlSettingEdit ctrlSetText ([_defaultValue, 1, _trailingDecimals] call 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 CBA_fnc_formatNumber); + } forEach _settingControls; + }; + default {}; + }; +}]; + +_linkedControls pushBack _ctrlSettingDefault; + +if !(_enabled) then { + _ctrlSettingDefault ctrlEnable false; +}; diff --git a/addons/settings/gui_createMenu_force.sqf b/addons/settings/gui_createMenu_force.sqf new file mode 100644 index 000000000..3a7fb7597 --- /dev/null +++ b/addons/settings/gui_createMenu_force.sqf @@ -0,0 +1,38 @@ +// inline function, don't include script_component.hpp + +private _ctrlSettingForce = _display ctrlCreate ["RscCheckBox", count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; +_contols pushBack _ctrlSettingForce; + +_ctrlSettingForce ctrlSetPosition [ + POS_W(33), + POS_H(_ctrlOptionsGroup getVariable QGVAR(offsetY)), + POS_W(1), + POS_H(1) +]; +_ctrlSettingForce ctrlCommit 0; +_ctrlSettingForce cbSetChecked ([_setting, _source] call FUNC(isForced)); + +private _data = [_setting, _source]; + +_ctrlSettingForce setVariable [QGVAR(linkedControls), _linkedControls]; +_ctrlSettingForce setVariable [QGVAR(data), _data]; + +if (_isGlobal) then { + _ctrlSettingForce ctrlSetChecked true; + _ctrlSettingForce ctrlEnable false; +}; + +_ctrlSettingForce ctrlAddEventHandler ["CheckedChanged", { + params ["_control", "_state"]; + + private _value = _state == 1; + + (_control getVariable QGVAR(data)) params ["_setting", "_source"]; + SET_TEMP_NAMESPACE_FORCED(_setting,_value,_source); +}]; + +_linkedControls pushBack _ctrlSettingForce; + +if !(_enabled) then { + _ctrlSettingForce ctrlEnable false; +}; diff --git a/addons/settings/gui_createMenu_list.sqf b/addons/settings/gui_createMenu_list.sqf new file mode 100644 index 000000000..ca50218d6 --- /dev/null +++ b/addons/settings/gui_createMenu_list.sqf @@ -0,0 +1,54 @@ +// inline function, don't include script_component.hpp + +private _ctrlSetting = _display ctrlCreate ["RscCombo", count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; +_contols pushBack _ctrlSetting; + +_ctrlSetting ctrlSetPosition [ + POS_W(16), + POS_H(_offsetY), + POS_W(10), + POS_H(1) +]; +_ctrlSetting ctrlCommit 0; + +_settingData params ["_values", "_labels"]; + +private _data = [_setting, _source, []]; + +{ + private _label = _labels select _forEachIndex; + + if (isLocalized _label) then { + _label = localize _label; + }; + + private _index = _ctrlSetting lbAdd _label; + _ctrlSetting lbSetData [_index, str _index]; + (_data select 2) set [_index, _x]; +} forEach _values; + +_ctrlSetting lbSetCurSel (_values find _currentValue); + +_ctrlSetting setVariable [QGVAR(linkedControls), _linkedControls]; +_ctrlSetting setVariable [QGVAR(data), _data]; + +_ctrlSetting ctrlAddEventHandler ["LBSelChanged", { + params ["_control", "_index"]; + + (_control getVariable QGVAR(data)) params ["_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_createMenu_slider.sqf b/addons/settings/gui_createMenu_slider.sqf new file mode 100644 index 000000000..1a1dfcfe8 --- /dev/null +++ b/addons/settings/gui_createMenu_slider.sqf @@ -0,0 +1,87 @@ +// inline function, don't include script_component.hpp + +private _ctrlSetting = _display ctrlCreate ["RscXSliderH", count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; +_contols pushBack _ctrlSetting; + +_ctrlSetting ctrlSetPosition [ + POS_W(16), + POS_H(_offsetY), + POS_W(8), + POS_H(1) +]; +_ctrlSetting ctrlCommit 0; + +_settingData params ["_min", "_max", "_trailingDecimals"]; + +_ctrlSetting sliderSetRange [_min, _max]; +_ctrlSetting sliderSetPosition _currentValue; + +private _data = [_setting, _source, _trailingDecimals]; + +_ctrlSetting setVariable [QGVAR(linkedControls), _linkedControls]; +_ctrlSetting setVariable [QGVAR(data), _data]; + +_ctrlSetting ctrlAddEventHandler ["SliderPosChanged", { + params ["_control", "_value"]; + + (_control getVariable QGVAR(data)) params ["_setting", "_source", "_trailingDecimals"]; + + private _linkedControl = _control getVariable QGVAR(linkedControls) select 1; + _linkedControl ctrlSetText ([_value, 1, _trailingDecimals] call CBA_fnc_formatNumber); + + SET_TEMP_NAMESPACE_VALUE(_setting,_value,_source); +}]; + +private _ctrlSettingEdit = _display ctrlCreate ["RscEdit", count _contols + IDC_OFFSET_SETTING, _ctrlOptionsGroup]; +_contols pushBack _ctrlSettingEdit; + +_ctrlSettingEdit ctrlSetPosition [ + POS_W(24), + POS_H(_offsetY), + POS_W(2), + POS_H(1) +]; +_ctrlSettingEdit ctrlCommit 0; +_ctrlSettingEdit ctrlSetText ([_currentValue, 1, _trailingDecimals] call CBA_fnc_formatNumber); + +_ctrlSettingEdit setVariable [QGVAR(linkedControls), _linkedControls]; +_ctrlSettingEdit setVariable [QGVAR(data), _data]; + +_ctrlSettingEdit ctrlAddEventHandler ["KeyUp", { + params ["_control"]; + + (_control getVariable QGVAR(data)) params ["_setting", "_source", "_trailingDecimals"]; + + private _value = parseNumber ctrlText _control; + + private _linkedControl = _control getVariable QGVAR(linkedControls) select 0; + _linkedControl sliderSetPosition _value; + + _value = sliderPosition _linkedControl; + SET_TEMP_NAMESPACE_VALUE(_setting,_value,_source); +}]; + +_ctrlSettingEdit ctrlAddEventHandler ["KillFocus", { + params ["_control"]; + + (_control getVariable QGVAR(data)) params ["", "", "_trailingDecimals"]; + + private _linkedControl = _control getVariable QGVAR(linkedControls) select 0; + private _value = sliderPosition _linkedControl; + + _control ctrlSetText ([_value, 1, _trailingDecimals] call 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_initDisplay.sqf b/addons/settings/gui_initDisplay.sqf new file mode 100644 index 000000000..b11a1efaf --- /dev/null +++ b/addons/settings/gui_initDisplay.sqf @@ -0,0 +1,122 @@ +#include "script_component.hpp" + +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 _categories = []; + +// ----- create settings lists + +#include "gui_createMenu.sqf" + +// ----- fill addons list +{ + private _category = _x; + + private _index = _ctrlAddonList lbAdd _category; + + _ctrlAddonList lbSetData [_index, str _index]; + _display setVariable [str _index, _category]; +} forEach _categories; + +lbSort _ctrlAddonList; +_ctrlAddonList lbSetCurSel (uiNamespace getVariable [QGVAR(addonIndex), 0]); + +// ----- create save and load presets buttons +private _ctrlButtonSave = _display ctrlCreate ["RscButtonMenu", IDC_BTN_SAVE]; + +_ctrlButtonSave ctrlSetPosition [ + POS_X(1.5), + POS_Y(20.5), + POS_W(6), + POS_H(1) +]; + +_ctrlButtonSave ctrlCommit 0; +_ctrlButtonSave ctrlSetText localize "STR_DISP_INT_SAVE"; +_ctrlButtonSave ctrlSetTooltip localize LSTRING(ButtonSave_tooltip); +_ctrlButtonSave ctrlEnable false; +_ctrlButtonSave ctrlShow false; +_ctrlButtonSave ctrlAddEventHandler ["ButtonClick", {[ctrlParent (_this select 0), "save"] call FUNC(gui_preset)}]; + +private _ctrlButtonLoad = _display ctrlCreate ["RscButtonMenu", IDC_BTN_LOAD]; + +_ctrlButtonLoad ctrlSetPosition [ + POS_X(7.6), + POS_Y(20.5), + POS_W(6), + POS_H(1) +]; + +_ctrlButtonLoad ctrlCommit 0; +_ctrlButtonLoad ctrlSetText localize "STR_DISP_INT_LOAD"; +_ctrlButtonLoad ctrlSetTooltip localize LSTRING(ButtonLoad_tooltip); +_ctrlButtonLoad ctrlEnable false; +_ctrlButtonLoad ctrlShow false; +_ctrlButtonLoad ctrlAddEventHandler ["ButtonClick", {[ctrlParent (_this select 0), "load"] call FUNC(gui_preset)}]; + +// ----- create export and import buttons +private _ctrlButtonImport = _display ctrlCreate ["RscButtonMenu", IDC_BTN_IMPORT]; + +_ctrlButtonImport ctrlSetPosition [ + POS_X(24.4), + POS_Y(20.5), + POS_W(6), + POS_H(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 [ + POS_X(30.5), + POS_Y(20.5), + POS_W(6), + POS_H(1) +]; + +_ctrlButtonExport ctrlCommit 0; +_ctrlButtonExport ctrlSetText localize LSTRING(ButtonExport); +_ctrlButtonExport ctrlSetTooltip localize LSTRING(ButtonExport_tooltip); +_ctrlButtonExport ctrlEnable false; +_ctrlButtonExport ctrlShow false; +_ctrlButtonExport ctrlAddEventHandler ["ButtonClick", {copyToClipboard ([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 CBA_fnc_createNamespace; +GVAR(serverSettingsTemp) = [] call CBA_fnc_createNamespace; +GVAR(missionSettingsTemp) = [] call 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_initDisplay_disabled.sqf b/addons/settings/gui_initDisplay_disabled.sqf new file mode 100644 index 000000000..db2752ae8 --- /dev/null +++ b/addons/settings/gui_initDisplay_disabled.sqf @@ -0,0 +1,16 @@ +#include "script_component.hpp" + +params ["_display"]; + +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; + +_ctrlToggleButton ctrlEnable false; + +{ + _x ctrlEnable false; + _x ctrlShow false; +} forEach [_ctrlAddonsGroup, _ctrlClientButton, _ctrlServerButton, _ctrlMissionButton]; diff --git a/addons/settings/init3DEN.sqf b/addons/settings/init3DEN.sqf new file mode 100644 index 000000000..c6f4da5b5 --- /dev/null +++ b/addons/settings/init3DEN.sqf @@ -0,0 +1,15 @@ +#include "script_component.hpp" + +private _fnc_resetMissionSettings = { + // --- delete settings from previous mission + GVAR(missionSettings) call CBA_fnc_deleteNamespace; + GVAR(missionSettings) = [] call CBA_fnc_createNamespace; + + GVAR(hash) = nil; + + // --- initialize settings of new mission + #include "initMissionSettings.sqf" +}; + +add3DENEventHandler ["onMissionNew", _fnc_resetMissionSettings]; +add3DENEventHandler ["onMissionLoad", _fnc_resetMissionSettings]; diff --git a/addons/settings/initMissionSettings.sqf b/addons/settings/initMissionSettings.sqf new file mode 100644 index 000000000..ddd7252ad --- /dev/null +++ b/addons/settings/initMissionSettings.sqf @@ -0,0 +1,21 @@ +// inline function, don't include script_component.hpp + +0 = 0 spawn { + { + // --- read previous setting values from mission + private _settingsHash = missionNamespace getVariable [QGVAR(hash), "Scenario" get3DENMissionAttribute QGVAR(hash)]; + + if (isNil "_settingsHash") then { + _settingsHash = NULL_HASH; + }; + + [_settingsHash, { + _value params ["_value", "_forced"]; + + GVAR(missionSettings) setVariable [_key, [_value, _forced]]; + }] call CBA_fnc_hashEachPair; + + // --- refresh all settings now + QGVAR(refreshAllSettings) call CBA_fnc_localEvent; + } call CBA_fnc_directCall; +}; diff --git a/addons/settings/initSettings.sqf b/addons/settings/initSettings.sqf new file mode 100644 index 000000000..024cff6e9 --- /dev/null +++ b/addons/settings/initSettings.sqf @@ -0,0 +1,21 @@ +// inline function, don't include script_component.hpp + +if (isNil QGVAR(defaultSettings)) then { + GVAR(defaultSettings) = [] call CBA_fnc_createNamespace; + GVAR(allSettings) = []; + + GVAR(clientSettings) = [] call CBA_fnc_createNamespace; + + if (isMultiplayer) then { + if (isServer) then { + GVAR(serverSettings) = true call CBA_fnc_createNamespace; + publicVariable QGVAR(serverSettings); + }; + } else { + GVAR(serverSettings) = false call CBA_fnc_createNamespace; + }; + + GVAR(missionSettings) = [] call CBA_fnc_createNamespace; + + #include "initMissionSettings.sqf" +}; 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/openSettingsMenu.sqf b/addons/settings/openSettingsMenu.sqf new file mode 100644 index 000000000..73719154d --- /dev/null +++ b/addons/settings/openSettingsMenu.sqf @@ -0,0 +1,43 @@ +#include "script_component.hpp" + +disableSerialization; + +params [["_display", findDisplay 46, [displayNull]]]; + +private _dlgSettings = _display createDisplay "RscDisplayGameOptions"; + +// switch to custom addons tab now +private _ctrlConfigureAddons = _dlgSettings displayCtrl IDC_BTN_CONFIGURE_ADDONS; +_ctrlConfigureAddons call FUNC(gui_configure); + +// and hide the button to switch back +_ctrlConfigureAddons ctrlEnable false; +_ctrlConfigureAddons ctrlShow false; + +// then switch right to missions tab +if (ctrlIDD _display == 313) then { + private _ctrlMissionButton = _dlgSettings displayCtrl IDC_BTN_MISSION; + _ctrlMissionButton call FUNC(gui_sourceChanged); +}; + +if (ctrlIDD _display in [37, 52, 53]) then { + private _ctrlButtonCancel = _display displayCtrl 2; + private _ctrlButtonSettings = _display displayCtrl IDC_BTN_SETTINGS; + + _ctrlButtonCancel ctrlEnable false; + _ctrlButtonCancel ctrlShow false; + _ctrlButtonSettings ctrlEnable false; + _ctrlButtonSettings ctrlShow false; + + [_dlgSettings, "unload", { + _thisArgs params ["_display"]; + + private _ctrlButtonCancel = _display displayCtrl 2; + private _ctrlButtonSettings = _display displayCtrl IDC_BTN_SETTINGS; + + _ctrlButtonCancel ctrlEnable true; + _ctrlButtonCancel ctrlShow true; + _ctrlButtonSettings ctrlEnable true; + _ctrlButtonSettings ctrlShow true; + }, [_display]] call CBA_fnc_addBISEventHandler; +}; diff --git a/addons/settings/script_component.hpp b/addons/settings/script_component.hpp new file mode 100644 index 000000000..ca4529c93 --- /dev/null +++ b/addons/settings/script_component.hpp @@ -0,0 +1,90 @@ +#define COMPONENT settings +#include "\x\cba\addons\main\script_mod.hpp" +#include "\x\cba\addons\main\script_macros.hpp" + +#include "\a3\ui_f\hpp\defineDIKCodes.inc" +#include "\a3\ui_f\hpp\defineCommonGrids.inc" + +//#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_BTN_SAVE 9020 +#define IDC_BTN_LOAD 9021 +#define IDC_TXT_FORCE 327 +#define IDC_OFFSET_SETTING 10000 +#define IDC_BTN_SETTINGS 7000 + +#define IDC_PRESETS_GROUP 8000 +#define IDC_PRESETS_TITLE 8001 +#define IDC_PRESETS_NAME 8002 +#define IDC_PRESETS_EDIT 8003 +#define IDC_PRESETS_VALUE 8004 +#define IDC_PRESETS_OK 8005 +#define IDC_PRESETS_CANCEL 8006 +#define IDC_PRESETS_DELETE 8007 + +#define POS_X(N) ((N) * GUI_GRID_W + GUI_GRID_X) +#define POS_Y(N) ((N) * GUI_GRID_H + GUI_GRID_Y) +#define POS_W(N) ((N) * GUI_GRID_W) +#define POS_H(N) ((N) * GUI_GRID_H) + +#define POS_X_CENTERED(N) ((N) * GUI_GRID_W + GUI_GRID_CENTER_X) +#define POS_Y_CENTERED(N) ((N) * GUI_GRID_H + GUI_GRID_CENTER_Y) + +#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 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]] + +#define MENU_OFFSET_INITIAL 0.3 +#define MENU_OFFSET_SPACING 1.4 +#define MENU_OFFSET_COLOR 1.0 +#define MENU_OFFSET_COLOR_NEG -0.7 + +#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 + +// replacement for "LOCATION getVariable [STRING, ANY]" +#define NAMESPACE_GETVAR(namespace,varname,default) ([namespace getVariable varname] param [0, default]) + +#define GET_VALUE(namespace,setting) ((GVAR(namespace) getVariable setting) param [0]) +#define GET_FORCED(namespace,setting) ((NAMESPACE_GETVAR(namespace,setting,[]) param [1, false]) || {isMultiplayer && {NAMESPACE_GETVAR(GVAR(defaultSettings),setting,[]) param [7, false]}}) + +#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)])] + +#define GET_TEMP_NAMESPACE_VALUE(setting,source) ((GET_TEMP_NAMESPACE(source) getVariable setting) param [0]) +#define GET_TEMP_NAMESPACE_FORCED(setting,source) ((GET_TEMP_NAMESPACE(source) getVariable setting) param [1]) + +#define NULL_HASH ([] call CBA_fnc_hashCreate) diff --git a/addons/settings/stringtable.xml b/addons/settings/stringtable.xml new file mode 100644 index 000000000..4961adbb6 --- /dev/null +++ b/addons/settings/stringtable.xml @@ -0,0 +1,84 @@ + + + + Community Base Addons - Settings Component + + + 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. + + + Game Options (Addons) + Optionen (Modifikationen) + + + Save current settings as preset. + Derzeitige Einstellungen als Vorlage speichern. + + + Load settings from preset. + Einstellungen aus Vorlage laden. + + 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..66c7f2b70 --- /dev/null +++ b/addons/settings_helper/config.cpp @@ -0,0 +1,19 @@ +// 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 { + author = "$STR_CBA_Author"; + name = ECSTRING(settings,component); + url = "$STR_CBA_URL"; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {}; + version = VERSION; + }; +}; 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)