diff --git a/AUTHORS.txt b/AUTHORS.txt index eff7e29bc..a51e668ea 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -50,6 +50,7 @@ PlayerBot Ryan180602 shukari SilentSpike +Timi007 Toinane Tuupertunut veteran29 diff --git a/README.md b/README.md index 714a0909f..20b0adb3b 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Special thanks to the [ACE3 Team](http://ace3mod.com/team.html) for their open s - Settings to control Zeus camera properties such as speed and available vision modes. - Zeus camera flashlight for easier editing at night. - New waypoint types such as paradrop available through Zeus. +- Ability to place comments and see comments created in 3DEN. ## Contributing diff --git a/addons/comments/$PBOPREFIX$ b/addons/comments/$PBOPREFIX$ new file mode 100644 index 000000000..89d5574df --- /dev/null +++ b/addons/comments/$PBOPREFIX$ @@ -0,0 +1 @@ +x\zen\addons\comments diff --git a/addons/comments/Cfg3DEN.hpp b/addons/comments/Cfg3DEN.hpp new file mode 100644 index 000000000..f1e7d2a3b --- /dev/null +++ b/addons/comments/Cfg3DEN.hpp @@ -0,0 +1,61 @@ +class Cfg3DEN { + class Attributes { + class Default; + class GVAR(hiddenAttribute): Default { + onLoad = QUOTE((ctrlParentControlsGroup ctrlParentControlsGroup (_this select 0)) ctrlShow false); + }; + }; + + class Mission { + class Scenario { + class AttributeCategories { + class ADDON { + displayName = STR_DISPLAY_NAME; + collapsed = 1; + + class Attributes { + class GVAR(3DENComments) { + displayName = STR_DISPLAY_NAME; + property = QGVAR(3DENComments); + control = QGVAR(hiddenAttribute); + tooltip = ""; + defaultValue = "[]"; + expression = ""; + wikiType = "[[Array]]"; + }; + }; + }; + }; + }; + }; + + class EventHandlers { + class ADDON { + // Arguments are for debugging + onMissionSave = QUOTE(['onMissionSave'] call FUNC(save3DENComments)); + onMissionAutosave = QUOTE(['onMissionAutosave'] call FUNC(save3DENComments)); + onBeforeMissionPreview = QUOTE(['onBeforeMissionPreview'] call FUNC(save3DENComments)); + }; + }; + + class Comment { + class AttributeCategories { + class ADDON { + displayName = ECSTRING(main,DisplayName); + collapsed = 0; + + class Attributes { + class GVAR(showComment) { + displayName = CSTRING(ShowCommentInZeus); + tooltip = CSTRING(ShowCommentInZeus_Description); + property = QGVAR(showComment); + control = "CheckboxState"; + defaultValue = "true"; + expression = ""; + wikiType = "[[Bool]]"; + }; + }; + }; + }; + }; +}; diff --git a/addons/comments/CfgContext.hpp b/addons/comments/CfgContext.hpp new file mode 100644 index 000000000..549a5fa28 --- /dev/null +++ b/addons/comments/CfgContext.hpp @@ -0,0 +1,9 @@ +class EGVAR(context_menu,actions) { + class GVAR(createComment) { + displayName = STR_CREATE_COMMENT; + icon = COMMENT_ICON; + condition = QGVAR(enabled); + statement = QUOTE([_position] call FUNC(openDialog)); + priority = 35; + }; +}; diff --git a/addons/comments/CfgEventHandlers.hpp b/addons/comments/CfgEventHandlers.hpp new file mode 100644 index 000000000..f6503c247 --- /dev/null +++ b/addons/comments/CfgEventHandlers.hpp @@ -0,0 +1,17 @@ +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); + }; +}; diff --git a/addons/comments/XEH_PREP.hpp b/addons/comments/XEH_PREP.hpp new file mode 100644 index 000000000..249276105 --- /dev/null +++ b/addons/comments/XEH_PREP.hpp @@ -0,0 +1,23 @@ +PREP(addDrawEventHandler); +PREP(createComment); +PREP(createIcon); +PREP(deleteComment); +PREP(deleteIcon); +PREP(drawComments); +PREP(is3DENComment); +PREP(moveComment); +PREP(onCommentCreated); +PREP(onCommentDeleted); +PREP(onCommentUpdated); +PREP(onDraw); +PREP(onDraw3D); +PREP(onKeyDown); +PREP(onMouseButtonDown); +PREP(onMouseButtonUp); +PREP(onMouseDblClick); +PREP(onMouseMoving); +PREP(onUnload); +PREP(openDialog); +PREP(save3DENComments); +PREP(updateComment); +PREP(updateIcon); diff --git a/addons/comments/XEH_postInit.sqf b/addons/comments/XEH_postInit.sqf new file mode 100644 index 000000000..e02720728 --- /dev/null +++ b/addons/comments/XEH_postInit.sqf @@ -0,0 +1,19 @@ +#include "script_component.hpp" + +if (isServer) then { + [QGVAR(createComment), LINKFUNC(createComment)] call CBA_fnc_addEventHandler; + [QGVAR(deleteComment), LINKFUNC(deleteComment)] call CBA_fnc_addEventHandler; + [QGVAR(updateComment), LINKFUNC(updateComment)] call CBA_fnc_addEventHandler; +}; + +if (hasInterface) then { + GVAR(comments) = createHashMapFromArray getMissionConfigValue [QGVAR(3DENComments), []]; + TRACE_1("Loaded 3DEN Comments from mission",GVAR(comments)); + + [QGVAR(commentCreated), LINKFUNC(onCommentCreated)] call CBA_fnc_addEventHandler; + [QGVAR(commentDeleted), LINKFUNC(onCommentDeleted)] call CBA_fnc_addEventHandler; + [QGVAR(commentUpdated), LINKFUNC(onCommentUpdated)] call CBA_fnc_addEventHandler; + + ["zen_curatorDisplayLoaded", LINKFUNC(addDrawEventHandler)] call CBA_fnc_addEventHandler; + ["zen_curatorDisplayUnloaded", LINKFUNC(onUnload)] call CBA_fnc_addEventHandler; +}; diff --git a/addons/comments/XEH_preInit.sqf b/addons/comments/XEH_preInit.sqf new file mode 100644 index 000000000..b4eb1efd5 --- /dev/null +++ b/addons/comments/XEH_preInit.sqf @@ -0,0 +1,27 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +if (isServer) then { + // Unique ID for creating comments + GVAR(nextID) = 0; +}; + +if (hasInterface) then { + // Map of all comments + // Keys are comment IDs and values are the data + GVAR(comments) = createHashMap; + GVAR(icons) = createHashMap; + + GVAR(draw3DAdded) = false; + + GVAR(movingComment) = []; +}; + +#include "initSettings.inc.sqf" + +ADDON = true; diff --git a/addons/comments/XEH_preStart.sqf b/addons/comments/XEH_preStart.sqf new file mode 100644 index 000000000..022888575 --- /dev/null +++ b/addons/comments/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/comments/config.cpp b/addons/comments/config.cpp new file mode 100644 index 000000000..38efcae04 --- /dev/null +++ b/addons/comments/config.cpp @@ -0,0 +1,22 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"zen_dialog"}; + author = ECSTRING(main,Author); + authors[] = {"Timi007"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +PRELOAD_ADDONS; + +#include "CfgEventHandlers.hpp" +#include "Cfg3DEN.hpp" +#include "CfgContext.hpp" +#include "gui.hpp" diff --git a/addons/comments/functions/fnc_addDrawEventHandler.sqf b/addons/comments/functions/fnc_addDrawEventHandler.sqf new file mode 100644 index 000000000..5c8eb0651 --- /dev/null +++ b/addons/comments/functions/fnc_addDrawEventHandler.sqf @@ -0,0 +1,37 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Function triggered every time the Zeus/Curator display is opened. + * Adds the draw event handlers to display 3DEN comments in 3D and on the map. + * + * Arguments: + * 0: Zeus Display + * + * Return Value: + * None + * + * Example: + * [_display] call zen_comments_fnc_addDrawEventHandler + * + * Public: No + */ + +params ["_display"]; +TRACE_1("Zeus display opened",_display); + +if (!GVAR(enabled) && !GVAR(enabled3DEN)) exitWith {}; + +[{ + {_x call FUNC(createIcon)} forEach GVAR(comments); +}] call CBA_fnc_execNextFrame; // Run next frame so display is loaded in FUNC(createIcon) + +if (!GVAR(draw3DAdded)) then { + LOG("Adding Draw3D."); + addMissionEventHandler ["Draw3D", {call FUNC(onDraw3D)}]; + GVAR(draw3DAdded) = true; +}; + +// MapDraw EH needs to be added every time the Zeus display is opened. +LOG("Adding map draw."); +private _ctrlMap = _display displayCtrl IDC_RSCDISPLAYCURATOR_MAINMAP; +_ctrlMap ctrlAddEventHandler ["Draw", {call FUNC(onDraw)}]; diff --git a/addons/comments/functions/fnc_createComment.sqf b/addons/comments/functions/fnc_createComment.sqf new file mode 100644 index 000000000..af3d0545d --- /dev/null +++ b/addons/comments/functions/fnc_createComment.sqf @@ -0,0 +1,44 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Creates a new comment in Zeus. + * + * Arguments: + * 0: Position ASL + * 1: Title + * 2: Tooltip (default: "") + * 3: Comment color (RGBA) (default: yellow) + * 4: Creator (default: "") + * 5: Lock position (default: false) + * + * Return Value: + * Id of the created comment . + * + * Example: + * [[0, 0, 0], "My Comment", "This is a nice comment", [1, 0, 0, 0.7], "Joe", false] call zen_comments_fnc_createComment + * + * Public: No + */ + +if (!isServer) exitWith { + [QGVAR(createComment), _this] call CBA_fnc_serverEvent; +}; + +params [ + ["_position", [0, 0, 0], [[]], 3], + ["_title", "", [""]], + ["_tooltip", "", [""]], + ["_color", DEFAULT_COLOR, [[]], 4], + ["_creator", "", [""]], + ["_lockPosition", false, [false]] +]; + +private _id = format ["%1:%2", COMMENT_TYPE_ZEUS, GVAR(nextID)]; +private _data = [_position, _title, _tooltip, _color, _creator, _lockPosition]; +GVAR(nextID) = GVAR(nextID) + 1; + +private _jipId = format [QGVAR(%1), _id]; +[QGVAR(commentCreated), [_id, _data], _jipId] call CBA_fnc_globalEventJIP; +TRACE_2("Comment created",_id,_data); + +_id diff --git a/addons/comments/functions/fnc_createIcon.sqf b/addons/comments/functions/fnc_createIcon.sqf new file mode 100644 index 000000000..993ed816d --- /dev/null +++ b/addons/comments/functions/fnc_createIcon.sqf @@ -0,0 +1,31 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Creates an icon control for the comment. + * + * Arguments: + * 0: Unique comment id + * + * Return Value: + * Icon control for the comment . + * + * Example: + * ["zeus:0"] call zen_comments_fnc_createIcon + * + * Public: No + */ + +params ["_id"]; + +private _display = findDisplay IDD_RSCDISPLAYCURATOR; +if (isNull _display || !(_id in GVAR(comments))) exitWith {}; + +(GVAR(comments) get _id) params ["", "", ["_tooltip", ""]]; + +private _ctrlIcon = _display ctrlCreate [QGVAR(RscActiveCommentIcon), -1]; +_ctrlIcon setVariable [QGVAR(comment), _id]; +_ctrlIcon ctrlSetTooltip _tooltip; + +GVAR(icons) set [_id, _ctrlIcon]; + +_ctrlIcon diff --git a/addons/comments/functions/fnc_deleteComment.sqf b/addons/comments/functions/fnc_deleteComment.sqf new file mode 100644 index 000000000..cdbe753cf --- /dev/null +++ b/addons/comments/functions/fnc_deleteComment.sqf @@ -0,0 +1,30 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Deletes the comment. + * + * Arguments: + * 0: Comment id + * + * Return Value: + * None + * + * Example: + * ["zeus:2"] call zen_comments_fnc_deleteComment + * + * Public: No + */ + +if (!isServer) exitWith { + [QGVAR(deleteComment), _this] call CBA_fnc_serverEvent; +}; + +params ["_id"]; + +// JIP event IDs are globally unique. For 3DEN comments, there won't be a created +// event but for Zeus ones the created JIP event will be overwritten with this +// deleted event that shares the same JIP ID, meaning that we don't have to remove +// the created JIP event. +private _jipId = format [QGVAR(%1), _id]; +[QGVAR(commentDeleted), [_id], _jipId] call CBA_fnc_globalEventJIP; +TRACE_1("Comment deleted",_id); diff --git a/addons/comments/functions/fnc_deleteIcon.sqf b/addons/comments/functions/fnc_deleteIcon.sqf new file mode 100644 index 000000000..c697dee6d --- /dev/null +++ b/addons/comments/functions/fnc_deleteIcon.sqf @@ -0,0 +1,22 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Deletes the icon control of comment. + * + * Arguments: + * 0: Comment id + * + * Return Value: + * None + * + * Example: + * ["zeus:2"] call zen_comments_fnc_deleteIcon + * + * Public: No + */ + +params ["_id"]; + +if (_id in GVAR(icons)) then { + ctrlDelete (GVAR(icons) deleteAt _id); +}; diff --git a/addons/comments/functions/fnc_drawComments.sqf b/addons/comments/functions/fnc_drawComments.sqf new file mode 100644 index 000000000..3fd0c6eeb --- /dev/null +++ b/addons/comments/functions/fnc_drawComments.sqf @@ -0,0 +1,150 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Draws comments on screen. Needs to be called every frame. + * + * Arguments: + * 0: Comments + * 1: Comment controls + * 2: Draw Zeus comments (Optional, default: true) + * 3: Draw 3DEN comments (Optional, default: true) + * 4: Map control (Optional, default: Draw in 3D) + * + * Return Value: + * None + * + * Example: + * [_comments, _icons] call zen_comments_fnc_drawComments + * + * Public: No + */ + +params ["_comments", "_icons", ["_drawZeus", true, [true]], ["_draw3DEN", true, [true]], ["_mapCtrl", controlNull, [controlNull]]]; + +private _drawIn3D = isNull _mapCtrl; + +private _d = 0; +private _scale = 0; +private _screenPos = []; + +{ + private _id = _x; + _y params ["_posASL", "_title", "_tooltip", ["_color", []], ["_creator", ""]]; + + private _ctrlIcon = _icons getOrDefault [_id, controlNull]; + if (isNull _ctrlIcon) then { + continue; + }; + + private _is3DENComment = _creator isEqualTo ""; // Faster then calling FUNC(is3DENComment) + if ((!_is3DENComment && !_drawZeus) || (_is3DENComment && !_draw3DEN)) then { + _ctrlIcon ctrlShow false; + continue; + }; + + private _posAGL = ASLToAGL _posASL; + + if (_drawIn3D) then { + _d = _posASL distance (getPosASLVisual curatorCamera); + _scale = linearConversion [SCALE_DISTANCE_START, MAX_RENDER_DISTANCE, _d, ICON_SCALE, 0, true]; + + _screenPos = curatorCamera worldToScreen _posAGL; + } else { + _scale = MAP_ICON_SCALE; + + _screenPos = _mapCtrl ctrlMapWorldToScreen _posAGL; + }; + + // Don't draw icon if it's too small or outside screen + if (_scale < 0.01 || {_screenPos isEqualTo []}) then { + _ctrlIcon ctrlShow false; + continue; + }; + _ctrlIcon ctrlShow true; + + if (_color isEqualTo []) then { + if (_is3DENComment) then { + _color = GVAR(3DENColor); + } else { + _color = DEFAULT_COLOR; + }; + }; + private _activeColor = [_color select 0, _color select 1, _color select 2, 1]; + + _ctrlIcon ctrlSetTextColor _color; + _ctrlIcon ctrlSetActiveColor _activeColor; + + _screenPos params ["_posX", "_posY"]; + private _posW = POS_W(_scale); + private _posH = POS_H(_scale); + + _ctrlIcon ctrlSetPosition [_posX - _posW / 2, _posY - _posH / 2, _posW, _posH]; + _ctrlIcon ctrlCommit 0; + + private _currentColor = [_color, _activeColor] select (_ctrlIcon getVariable [QGVAR(isActive), false]); + + if (_drawIn3D) then { + // Draw comment name and connection line in 3D + private _textOffsetScale = linearConversion [SCALE_DISTANCE_START, MAX_RENDER_DISTANCE, _d, 1, MIN_TEXT_OFFSET_SCALE, true]; + private _uiScale = getResolution select 5; + private _textOffsetY = TEXT_OFFSET_Y * _textOffsetScale * _uiScale; + + drawIcon3D [ + "", + _currentColor, + _posAGL, + _scale, // Width + _scale, // Height + 0, // Angle + _title, // Text + 1, // Shadow + -1, // Text Size + "RobotoCondensed", // Font + "center", // Align + false, // Arrows + 0, // Offset X + _textOffsetY // Offset Y + ]; + + if (_creator isNotEqualTo "") then { + drawIcon3D [ + "", + _currentColor, + _posAGL, + _scale, // Width + _scale, // Height + 0, // Angle + _creator, // Text + 1, // Shadow + -1, // Text Size + "RobotoCondensedBold" // Font + ]; + }; + + // Draw ground-icon connection line only for icons higher than X m + if ((_posAGL select 2) > GROUND_ICON_CONNECTION_HEIGHT) then { + // Hide line behind icon + drawLine3D [_posAGL vectorAdd [0, 0, -0.05], [_posAGL select 0, _posAGL select 1, 0], _currentColor]; + }; + } else { + // Draw comment name on map + private _text = switch (true) do { + case (_creator isEqualTo ""): {_title}; // Case for 3DEN comment + case (_title isEqualTo ""): {_creator}; // Case for Zeus comment without title + default {format ["%1: %2", _creator, _title]}; // Case for Zeus comment with title + }; + + _mapCtrl drawIcon [ + "#(argb,8,8,3)color(0,0,0,0)", + _currentColor, + _posASL, + MAP_TEXT_SCALE, // Width + MAP_TEXT_SCALE, // Height + 0, // Angle + _text, // Text + 1, // Shadow + -1, // Text Size + "RobotoCondensed" // Font + ]; + }; +} forEach _comments; diff --git a/addons/comments/functions/fnc_is3DENComment.sqf b/addons/comments/functions/fnc_is3DENComment.sqf new file mode 100644 index 000000000..1168849b8 --- /dev/null +++ b/addons/comments/functions/fnc_is3DENComment.sqf @@ -0,0 +1,22 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Checks if comment with given id is an 3DEN comment. + * + * Arguments: + * 0: Comment id + * + * Return Value: + * Is an 3DEN comment + * + * Example: + * ["3den:2"] call zen_comments_fnc_is3DENComment + * + * Public: No + */ + +params ["_id"]; + +(_id splitString ":") params [["_type", "", [""]]]; + +_type isEqualTo COMMENT_TYPE_3DEN diff --git a/addons/comments/functions/fnc_moveComment.sqf b/addons/comments/functions/fnc_moveComment.sqf new file mode 100644 index 000000000..82c4d7ab7 --- /dev/null +++ b/addons/comments/functions/fnc_moveComment.sqf @@ -0,0 +1,34 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Move a comment. + * + * Arguments: + * 0: Icon control + * 1: New position ASL + * 2: Move only locally (default: false) + * + * Return Value: + * None + * + * Example: + * ["zeus:0", [0, 0, 0], true] call zen_comments_fnc_moveComment + * + * Public: No + */ + +params [ + ["_id", "", [""]], + ["_position", [0, 0, 0], [[]], 3], + ["_local", false, [false]] +]; + +private _data = GVAR(comments) getOrDefault [_id, []]; +if (_data isEqualTo []) exitWith {}; +_data set [0, _position]; + +if (_local) then { + [QGVAR(commentUpdated), [_id, _data]] call CBA_fnc_localEvent; +} else { + [QGVAR(updateComment), [_id] + _data] call CBA_fnc_serverEvent; +}; diff --git a/addons/comments/functions/fnc_onCommentCreated.sqf b/addons/comments/functions/fnc_onCommentCreated.sqf new file mode 100644 index 000000000..47b6eb73a --- /dev/null +++ b/addons/comments/functions/fnc_onCommentCreated.sqf @@ -0,0 +1,23 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Creates the comment locally. + * + * Arguments: + * 0: Unique comment id + * 1: Comment data + * + * Return Value: + * None + * + * Example: + * ["zeus:1", [[0,0,0], "My Comment", "This is a nice comment", [1,0,0,0.7], "Joe"]] call zen_comments_fnc_onCommentCreated + * + * Public: No + */ + +params ["_id", "_data"]; + +GVAR(comments) set [_id, _data]; + +[_id] call FUNC(createIcon); diff --git a/addons/comments/functions/fnc_onCommentDeleted.sqf b/addons/comments/functions/fnc_onCommentDeleted.sqf new file mode 100644 index 000000000..88bdae2d3 --- /dev/null +++ b/addons/comments/functions/fnc_onCommentDeleted.sqf @@ -0,0 +1,22 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Deletes the comment locally. + * + * Arguments: + * 0: Comment id + * + * Return Value: + * None + * + * Example: + * ["zeus:2"] call zen_comments_fnc_onCommentDeleted + * + * Public: No + */ + +params ["_id"]; + +GVAR(comments) deleteAt _id; + +[_id] call FUNC(deleteIcon); diff --git a/addons/comments/functions/fnc_onCommentUpdated.sqf b/addons/comments/functions/fnc_onCommentUpdated.sqf new file mode 100644 index 000000000..cd14b6e60 --- /dev/null +++ b/addons/comments/functions/fnc_onCommentUpdated.sqf @@ -0,0 +1,28 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Updates the comment locally. + * + * Arguments: + * 0: Comment id + * 1: Comment data + * + * Return Value: + * None + * + * Example: + * ["zeus:2", [[0,0,0], "My edited Comment", "This is a nice comment", [1,0,0,0.7], "Joe"]] call zen_comments_fnc_onCommentUpdated + * + * Public: No + */ + +params ["_id", "_data"]; + +if (_id in GVAR(comments)) then { + GVAR(comments) set [_id, _data]; + + [_id] call FUNC(updateIcon); +} else { + // Comment does not exist (JIP case). + [QGVAR(commentCreated), _this] call CBA_fnc_localEvent; +}; diff --git a/addons/comments/functions/fnc_onDraw.sqf b/addons/comments/functions/fnc_onDraw.sqf new file mode 100644 index 000000000..49fb3912a --- /dev/null +++ b/addons/comments/functions/fnc_onDraw.sqf @@ -0,0 +1,31 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles drawing the comments on the Zeus map. Is only called when map is open. + * + * Arguments: + * 0: Zeus map + * + * Return Value: + * None + * + * Example: + * [_mapCtrl] call zen_comments_fnc_onDraw + * + * Public: No + */ + +BEGIN_COUNTER(onDraw); + +params ["_mapCtrl"]; + +if (!GVAR(enabled) && !GVAR(enabled3DEN)) exitWith { + _mapCtrl ctrlRemoveEventHandler [_thisEvent, _thisEventHandler]; + LOG("Removed 3DENComments map draw."); +}; + +if (dialog || {call EFUNC(common,isInScreenshotMode)}) exitWith {}; // Dialog is open or HUD is hidden + +[GVAR(comments), GVAR(icons), GVAR(enabled), GVAR(enabled3DEN), _mapCtrl] call FUNC(drawComments); + +END_COUNTER(onDraw); diff --git a/addons/comments/functions/fnc_onDraw3D.sqf b/addons/comments/functions/fnc_onDraw3D.sqf new file mode 100644 index 000000000..735f694c7 --- /dev/null +++ b/addons/comments/functions/fnc_onDraw3D.sqf @@ -0,0 +1,41 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles drawing the comments in Zeus 3D. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * call zen_comments_fnc_onDraw3D + * + * Public: No + */ + +BEGIN_COUNTER(onDraw3D); + +if (!GVAR(enabled) && !GVAR(enabled3DEN)) exitWith { + removeMissionEventHandler [_thisEvent, _thisEventHandler]; + + {ctrlDelete _y} forEach GVAR(icons); + GVAR(icons) = createHashMap; + + GVAR(draw3DAdded) = false; + LOG("Removed Draw3D."); +}; + +if ( + isNull (findDisplay IDD_RSCDISPLAYCURATOR) || // We are in not Zeus + {!isNull (findDisplay IDD_INTERRUPT)} || // Pause menu is opened + {dialog} || // We have a dialog open + {call EFUNC(common,isInScreenshotMode)} // HUD is hidden +) exitWith { + {_y ctrlShow false} forEach GVAR(icons); +}; + +[GVAR(comments), GVAR(icons), GVAR(enabled), GVAR(enabled3DEN)] call FUNC(drawComments); + +END_COUNTER(onDraw3D); diff --git a/addons/comments/functions/fnc_onKeyDown.sqf b/addons/comments/functions/fnc_onKeyDown.sqf new file mode 100644 index 000000000..4385699e4 --- /dev/null +++ b/addons/comments/functions/fnc_onKeyDown.sqf @@ -0,0 +1,28 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles the key down event for a comment. + * + * Arguments: + * 0: Icon control + * 1: Key pressed + * + * Return Value: + * None + * + * Example: + * _this call zen_comments_fnc_onKeyDown + * + * Public: No + */ + +params ["_ctrlIcon", "_key"]; + +if (_key != DIK_DELETE) exitWith {}; + +private _id = _ctrlIcon getVariable [QGVAR(comment), ""]; +if (_id isEqualTo "") exitWith {}; + +if (!GVAR(allowDeleting3DEN) && {_id call FUNC(is3DENComment)}) exitWith {}; + +[QGVAR(deleteComment), [_id]] call CBA_fnc_serverEvent; diff --git a/addons/comments/functions/fnc_onMouseButtonDown.sqf b/addons/comments/functions/fnc_onMouseButtonDown.sqf new file mode 100644 index 000000000..7e8ba8ffb --- /dev/null +++ b/addons/comments/functions/fnc_onMouseButtonDown.sqf @@ -0,0 +1,30 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles the mouse button down event for start moving a comment. + * + * Arguments: + * 0: Icon control + * 1: Button pressed + * + * Return Value: + * None + * + * Example: + * _this call zen_comments_fnc_onMouseButtonDown + * + * Public: No + */ + +params ["_ctrlIcon", "_button"]; + +if (_button != 0) exitWith {}; + +private _id = _ctrlIcon getVariable [QGVAR(comment), ""]; +if (_id isEqualTo "" || {_id call FUNC(is3DENComment)}) exitWith {}; + +(GVAR(comments) get _id) params ["_position", "", "", "", "", "_lockPosition"]; + +if (_lockPosition) exitWith {}; + +GVAR(movingComment) = [_id, +_position]; diff --git a/addons/comments/functions/fnc_onMouseButtonUp.sqf b/addons/comments/functions/fnc_onMouseButtonUp.sqf new file mode 100644 index 000000000..9ba969900 --- /dev/null +++ b/addons/comments/functions/fnc_onMouseButtonUp.sqf @@ -0,0 +1,29 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles the mouse button down event for stop moving a comment. + * + * Arguments: + * 0: Icon control + * 1: Button pressed + * + * Return Value: + * None + * + * Example: + * _this call zen_comments_fnc_onMouseButtonUp + * + * Public: No + */ + +params ["_ctrlIcon", "_button"]; + +if (_button != 0 || GVAR(movingComment) isEqualTo []) exitWith {}; + +private _id = _ctrlIcon getVariable [QGVAR(comment), ""]; +if (_id isEqualTo "") exitWith {ERROR("Moving invalid comment.")}; + +private _position = [] call EFUNC(common,getPosFromScreen); +[_id, _position] call FUNC(moveComment); + +GVAR(movingComment) = []; diff --git a/addons/comments/functions/fnc_onMouseDblClick.sqf b/addons/comments/functions/fnc_onMouseDblClick.sqf new file mode 100644 index 000000000..0a5549625 --- /dev/null +++ b/addons/comments/functions/fnc_onMouseDblClick.sqf @@ -0,0 +1,28 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles the mouse button double click event for a comment. + * + * Arguments: + * 0: Icon control + * 1: Mouse button pressed + * + * Return Value: + * None + * + * Example: + * _this call zen_comments_fnc_onMouseDblClick + * + * Public: No + */ + +params ["_ctrlIcon", "_button"]; + +if (_button != 0) exitWith {}; + +private _id = _ctrlIcon getVariable [QGVAR(comment), ""]; +if (_id isEqualTo "" || {_id call FUNC(is3DENComment)}) exitWith {}; + +TRACE_1("Edit comment",_id); + +[_id] call FUNC(openDialog); diff --git a/addons/comments/functions/fnc_onMouseMoving.sqf b/addons/comments/functions/fnc_onMouseMoving.sqf new file mode 100644 index 000000000..03715e731 --- /dev/null +++ b/addons/comments/functions/fnc_onMouseMoving.sqf @@ -0,0 +1,26 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles the mouse moving event for moving a comment. + * + * Arguments: + * 0: Icon control + * + * Return Value: + * None + * + * Example: + * _this call zen_comments_fnc_onMouseMoving + * + * Public: No + */ + +params ["_ctrlIcon"]; + +if (GVAR(movingComment) isEqualTo []) exitWith {}; + +private _id = _ctrlIcon getVariable [QGVAR(comment), ""]; +if (_id isEqualTo "") exitWith {ERROR("Moving invalid comment.")}; + +private _position = [] call EFUNC(common,getPosFromScreen); +[_id, _position, true] call FUNC(moveComment); diff --git a/addons/comments/functions/fnc_onUnload.sqf b/addons/comments/functions/fnc_onUnload.sqf new file mode 100644 index 000000000..b00fc8de9 --- /dev/null +++ b/addons/comments/functions/fnc_onUnload.sqf @@ -0,0 +1,23 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Handles unloading the Zeus Display. + * + * Arguments: + * 0: Display + * + * Return Value: + * None + * + * Example: + * [DISPLAY] call zen_comments_fnc_onUnload + * + * Public: No + */ + +if (GVAR(movingComment) isNotEqualTo []) then { + // Zeus displayed closed before moving stopped + // Reset comment back to original position + GVAR(movingComment) call FUNC(moveComment); + GVAR(movingComment) = []; +}; diff --git a/addons/comments/functions/fnc_openDialog.sqf b/addons/comments/functions/fnc_openDialog.sqf new file mode 100644 index 000000000..79a252205 --- /dev/null +++ b/addons/comments/functions/fnc_openDialog.sqf @@ -0,0 +1,57 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Opens the dialog for creating a comment. + * + * Arguments: + * 0: Position ASL or Comment ID + * + * Return Value: + * None + * + * Example: + * [[0, 0, 0]] call zen_comments_fnc_openDialog + * ["zeus:0"] call zen_comments_fnc_openDialog + * + * Public: No + */ + +params ["_positionOrId"]; + +private _id = ["", _positionOrId] select (_positionOrId isEqualType ""); +private _isEditingComment = _id isNotEqualTo ""; + +(GVAR(comments) getOrDefault [_id, []]) params [ + ["_position", [], [[]], 3], + ["_title", "", [""]], + ["_tooltip", "", [""]], + ["_color", DEFAULT_COLOR, [[]], 4], + ["_creator", "", [""]], + ["_lockPosition", false, [false]] +]; + +if (_positionOrId isEqualType [] && _position isEqualTo []) then { + _position = _positionOrId; +}; + +[ + localize STR_CREATE_COMMENT, + [ + ["EDIT", localize "str_3den_comment_attribute_name_displayname", [_title], true], + ["EDIT:MULTI", localize "str_3den_comment_attribute_name_tooltip", [_tooltip], true], + ["TOOLBOX:YESNO", LLSTRING(LockPosition), [_lockPosition], _isEditingComment], + ["COLOR", localize "str_3den_marker_attribute_color_displayname", _color, _isEditingComment] + ], + { + (_this select 0) params ["_title", "_tooltip", "_lockPosition", "_color"]; + (_this select 1) params ["_id", "_position"]; + + if (_id isEqualTo "") then { + [QGVAR(createComment), [_position, _title, _tooltip, _color, profileName, _lockPosition]] call CBA_fnc_serverEvent; + } else { + [QGVAR(updateComment), [_id, _position, _title, _tooltip, _color, profileName, _lockPosition]] call CBA_fnc_serverEvent; + }; + }, + {}, + [_id, _position] +] call EFUNC(dialog,create); diff --git a/addons/comments/functions/fnc_save3DENComments.sqf b/addons/comments/functions/fnc_save3DENComments.sqf new file mode 100644 index 000000000..b21242d0e --- /dev/null +++ b/addons/comments/functions/fnc_save3DENComments.sqf @@ -0,0 +1,42 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Function called when 3DEN save event is triggered. + * Handles saving comments into scenario space for later use. + * + * Arguments: + * 0: Event that triggered this function (for debug purposes) + * + * Return Value: + * None + * + * Example: + * call zen_comments_fnc_save3DENComments + * + * Public: No + */ + +params [["_event", "", [""]]]; + +if (!is3DEN) exitWith {}; + +private _comments = []; +{ + // all3DENEntities always includes this id, ignore it + if (_x isEqualTo -999) then {continue}; + + private _show = (_x get3DENAttribute QGVAR(showComment)) select 0; + if (!_show) then {continue}; + + private _id = format ["%1:%2", COMMENT_TYPE_3DEN, _x]; + private _position = (_x get3DENAttribute "position") select 0; + private _title = (_x get3DENAttribute "name") select 0; + private _tooltip = (_x get3DENAttribute "description") select 0; + + // Save in hashmap format with id as key + _comments pushBack [_id, [_position, _title, _tooltip]]; +} forEach (all3DENEntities select 7); + +// This command does not work if the mission is not saved +set3DENMissionAttributes [["Scenario", QGVAR(3DENComments), _comments]]; +TRACE_2("Saved 3DEN comments",_event,_comments); diff --git a/addons/comments/functions/fnc_updateComment.sqf b/addons/comments/functions/fnc_updateComment.sqf new file mode 100644 index 000000000..b582b62ef --- /dev/null +++ b/addons/comments/functions/fnc_updateComment.sqf @@ -0,0 +1,41 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Updates the comment. + * + * Arguments: + * 0: Unique comment id + * 1: Position ASL + * 2: Title + * 3: Tooltip + * 4: Comment color (RGBA) + * 5: Creator + * 6: Lock position + * + * Return Value: + * None + * + * Example: + * ["zeus:2", [0, 0, 0], "My updated Comment", "This is a nice comment", [1, 0, 0, 0.7], "Joe", false] call zen_comments_fnc_updateComment + * + * Public: No + */ + +if (!isServer) exitWith { + [QGVAR(updateComment), _this] call CBA_fnc_serverEvent; +}; + +params [ + ["_id", "", [""]], + ["_position", [0, 0, 0], [[]], 3], + ["_title", "", [""]], + ["_tooltip", "", [""]], + ["_color", DEFAULT_COLOR, [[]], 4], + ["_creator", "", [""]], + ["_lockPosition", false, [false]] +]; + +private _data = [_position, _title, _tooltip, _color, _creator, _lockPosition]; +private _jipId = format [QGVAR(%1), _id]; +[QGVAR(commentUpdated), [_id, _data], _jipId] call CBA_fnc_globalEventJIP; +TRACE_2("Comment updated",_id,_data); diff --git a/addons/comments/functions/fnc_updateIcon.sqf b/addons/comments/functions/fnc_updateIcon.sqf new file mode 100644 index 000000000..3c987c3c3 --- /dev/null +++ b/addons/comments/functions/fnc_updateIcon.sqf @@ -0,0 +1,25 @@ +#include "script_component.hpp" +/* + * Author: Timi007 + * Updates the icon control of comment. + * + * Arguments: + * 0: Comment id + * + * Return Value: + * None + * + * Example: + * ["zeus:2"] call zen_comments_fnc_updateIcon + * + * Public: No + */ + +params ["_id"]; + +private _ctrlIcon = GVAR(icons) getOrDefault [_id, controlNull]; +if (isNull _ctrlIcon || !(_id in GVAR(comments))) exitWith {}; + +(GVAR(comments) get _id) params ["", "", ["_tooltip", ""]]; + +_ctrlIcon ctrlSetTooltip _tooltip; diff --git a/addons/comments/functions/script_component.hpp b/addons/comments/functions/script_component.hpp new file mode 100644 index 000000000..b85e1ce6d --- /dev/null +++ b/addons/comments/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\x\zen\addons\comments\script_component.hpp" diff --git a/addons/comments/gui.hpp b/addons/comments/gui.hpp new file mode 100644 index 000000000..b2a404dda --- /dev/null +++ b/addons/comments/gui.hpp @@ -0,0 +1,20 @@ +class RscActivePicture; +class GVAR(RscActiveCommentIcon): RscActivePicture { + onMouseEnter = QUOTE((_this select 0) setVariable [ARR_2(QQGVAR(isActive),true)]; ctrlSetFocus (_this select 0)); // Set focus for KeyDown to register + onMouseExit = QUOTE((_this select 0) setVariable [ARR_2(QQGVAR(isActive),false)]); + + // For deleting comments + onKeyDown = QUOTE(call FUNC(onKeyDown)); + + // For editing comments + onMouseButtonDblClick = QUOTE(call FUNC(onMouseDblClick)); + + // For moving comments + onMouseButtonDown = QUOTE(call FUNC(onMouseButtonDown)); + onMouseButtonUp = QUOTE(call FUNC(onMouseButtonUp)); + onMouseMoving = QUOTE(call FUNC(onMouseMoving)); + + shadow = 1; + text = COMMENT_ICON; + tooltipMaxWidth = QUOTE(POS_W(15)); +}; diff --git a/addons/comments/initSettings.inc.sqf b/addons/comments/initSettings.inc.sqf new file mode 100644 index 000000000..ab10ab2c0 --- /dev/null +++ b/addons/comments/initSettings.inc.sqf @@ -0,0 +1,51 @@ +private _category = [ELSTRING(main,DisplayName), localize STR_DISPLAY_NAME]; + +[ + QGVAR(enabled), + "CHECKBOX", + [LLSTRING(Comments), LLSTRING(Comments_Description)], + _category, + true, + 0, + { + TRACE_1("Enable comments setting changed",_this); + + private _display = findDisplay IDD_RSCDISPLAYCURATOR; + if (!_this || GVAR(enabled3DEN) || isNull _display || GVAR(draw3DAdded)) exitWith {}; + [_display] call FUNC(addDrawEventHandler); + } +] call CBA_fnc_addSetting; + +[ + QGVAR(enabled3DEN), + "CHECKBOX", + [LLSTRING(3DENComments), LLSTRING(3DENComments_Description)], + _category, + true, + 0, + { + TRACE_1("Enable 3DEN comments setting changed",_this); + + private _display = findDisplay IDD_RSCDISPLAYCURATOR; + if (!_this || GVAR(enabled) || isNull _display || GVAR(draw3DAdded)) exitWith {}; + [_display] call FUNC(addDrawEventHandler); + } +] call CBA_fnc_addSetting; + +[ + QGVAR(3DENColor), + "COLOR", + [LLSTRING(3DENCommentColor), LLSTRING(3DENCommentColor_Description)], + _category, + [0, 1, 0.75, 0.7], + 0 +] call CBA_fnc_addSetting; + +[ + QGVAR(allowDeleting3DEN), + "CHECKBOX", + [LLSTRING(AllowDeleting3DENComments), LLSTRING(AllowDeleting3DENComments_Description)], + _category, + false, + 0 +] call CBA_fnc_addSetting; diff --git a/addons/comments/script_component.hpp b/addons/comments/script_component.hpp new file mode 100644 index 000000000..23c9d181c --- /dev/null +++ b/addons/comments/script_component.hpp @@ -0,0 +1,47 @@ +#define COMPONENT comments +#define COMPONENT_BEAUTIFIED Comments +#include "\x\zen\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_COMMENTS + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_COMMENTS + #define DEBUG_SETTINGS DEBUG_SETTINGS_COMMENTS +#endif + +#include "\x\zen\addons\main\script_macros.hpp" + +#include "\a3\ui_f\hpp\defineDIKCodes.inc" +#include "\a3\ui_f\hpp\defineCommonGrids.inc" +#include "\x\zen\addons\common\defineResinclDesign.inc" + +#define POS_X(N) ((N) * GUI_GRID_W + GUI_GRID_CENTER_X) +#define POS_Y(N) ((N) * GUI_GRID_H + GUI_GRID_CENTER_Y) +#define POS_W(N) ((N) * GUI_GRID_W) +#define POS_H(N) ((N) * GUI_GRID_H) + +#define COMMENT_ICON "a3\3den\Data\Cfg3DEN\Comment\texture_ca.paa" +#define ICON_SCALE 1 +#define MAP_ICON_SCALE 1.2 +#define MAP_TEXT_SCALE 24 + +#define TEXT_OFFSET_Y -0.076 +#define MIN_TEXT_OFFSET_SCALE 0.35 + +#define SCALE_DISTANCE_START 300 +#define MAX_RENDER_DISTANCE 750 + +#define GROUND_ICON_CONNECTION_HEIGHT 0.5 + +#define STR_DISPLAY_NAME "$STR_3DEN_Comment_textPlural" +#define STR_CREATE_COMMENT "$STR_3den_display3den_entitymenu_createcomment_text" + +#define COMMENT_TYPE_3DEN "3den" +#define COMMENT_TYPE_ZEUS "zeus" + +#define DEFAULT_COLOR [1, 1, 0, 0.7] diff --git a/addons/comments/stringtable.xml b/addons/comments/stringtable.xml new file mode 100644 index 000000000..3f172bda4 --- /dev/null +++ b/addons/comments/stringtable.xml @@ -0,0 +1,49 @@ + + + + + Enable comments in Zeus + Aktiviere Kommentare im Zeus + + + Allow creating comments in Zeus. + Erlaube das Erstellen von Kommentaren im Zeus. + + + Show 3DEN comments in Zeus + Zeige 3DEN-Kommentare im Zeus + + + Show 3DEN comments in Zeus. + Zeige 3DEN-Kommentare im Zeus an. + + + 3DEN comment color + Farbe der 3DEN-Kommentare + + + Color of 3DEN comments in Zeus. + Farbe der 3DEN-Kommentare im Zeus. + + + Allow deleting 3DEN comments + Erlaube Löschen von 3DEN-Kommentaren + + + Allow any Zeus to delete 3DEN comments. + Erlaube jedem Zeus das Löschen von 3DEN-Kommentaren. + + + Show comment in Zeus + Zeige Kommentar in Zeus + + + If selected, this comment will be shown in Zeus. + Wenn ausgewählt, wird dieser Kommentar in Zeus angezeigt. + + + Lock position + Position sperren + + + diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 1529f158f..a0e01c0a4 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -6,6 +6,7 @@ - [ Compositions](/user_guide/compositions.md) - [ Vehicle Garage](/user_guide/garage.md) - [ Area Markers](/user_guide/area_markers.md) + - [ Comments](/user_guide/comments.md) - **Frameworks** - [ Context Menu](/frameworks/context_menu.md) - [ Custom Modules](/frameworks/custom_modules.md) diff --git a/docs/home.md b/docs/home.md index 3704ecdb7..88c35785c 100644 --- a/docs/home.md +++ b/docs/home.md @@ -26,3 +26,4 @@ Special thanks to the [ACE3 Team](http://ace3mod.com/team.html) for their open s - Settings to control Zeus camera properties such as speed and available vision modes. - Zeus camera flashlight for easier editing at night. - New waypoint types such as paradrop available through Zeus. +- Ability to place comments and see comments created in 3DEN. diff --git a/docs/user_guide/comments.md b/docs/user_guide/comments.md new file mode 100644 index 000000000..9680ce8b5 --- /dev/null +++ b/docs/user_guide/comments.md @@ -0,0 +1,29 @@ +# Comments + +Zeus Enhanced adds the ability to create and edit comments through Zeus. +In addition, comments created in 3DEN are imported into Zeus. + +### Creating + +Comments can be created by using the context menu action. +The context menu action is only shown when comments are enabled in the CBA settings. + +### Editing + +The properties of comments can be changed by double clicking on the icon of the comment. +This will open a menu that allows you to configure the comment's title, tooltip, and color. + +Comments can be moved by left clicking and dragging on the icon. +Comments created in 3DEN cannot be moved. + +### Deleting + +Comments can be deleted by hovering over the icon and pressing the DELETE key. +By default, comments created in 3DEN cannot be deleted. This can be changed in the CBA settings. + +## 3DEN Comments {docsify-ignore} + +All comments created in 3DEN will be imported into Zeus by default. +A comment can be excluded by unchecking the "Show comment in Zeus" option when creating/editing a comment in 3DEN. + +!> The mission must be saved; otherwise, 3DEN comments will not be shown in Zeus! diff --git a/docs/user_guide/context_actions.md b/docs/user_guide/context_actions.md index 803ad90b1..0d7184882 100644 --- a/docs/user_guide/context_actions.md +++ b/docs/user_guide/context_actions.md @@ -60,6 +60,10 @@ Sub-actions allow for copying and pasting the hovered unit's loadout onto anothe Furthermore, the unit's current weapon can be switched between their rifle, handgun, or binoculars. The main action acts as a shortcut for the "Edit" sub-action. +## Place Comment + +Creates a [comment](/user_guide/comments.md) at the context menu's position. + ## Remote Control Starts the remote control process on the hovered unit or vehicle.