1 /**
2  * @file
3  * @todo Remove direct access to nodes
4  */
5 
6 /*
7 Copyright (C) 2002-2013 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 */
25 
26 #include "../../cl_shared.h"
27 /* UI_InitOptionIteratorAtIndex */
28 #include "../../ui/ui_main.h"
29 #include "../../ui/ui_data.h"
30 #include "cp_campaign.h"
31 #include "cp_messageoptions.h"
32 #include "cp_messageoptions_callbacks.h"
33 
34 static msoMenuState_t msoMenuState = MSO_MSTATE_REINIT;
35 static int messageList_size = 0; /**< actual messageSettings list size */
36 static int messageList_scroll = 0; /**< actual messageSettings list begin index due to scrolling */
37 static int visibleMSOEntries = 0; /**< actual visible entry count */
38 messageSettings_t backupMessageSettings[NT_NUM_NOTIFYTYPE]; /**< array holding backup message settings (used for restore function in options popup) */
39 
40 /**
41  * @brief Initializes menu texts for scrollable area
42  * @sa MSO_Init_f
43  */
MSO_InitList(void)44 static void MSO_InitList (void)
45 {
46 	uiNode_t* messageSetting = nullptr;
47 	uiNode_t* lastCategory = nullptr;
48 	int idx;
49 
50 	/* option already allocated, nothing to do */
51 	if (cgi->UI_GetOption(TEXT_MESSAGEOPTIONS) != nullptr)
52 		return;
53 
54 	cgi->UI_ResetData(TEXT_MESSAGEOPTIONS);
55 	for (idx = 0; idx < ccs.numMsgCategoryEntries; idx++) {
56 		const msgCategoryEntry_t* entry = &ccs.msgCategoryEntries[idx];
57 		const char* id = va("%d", idx);
58 
59 		if (entry->isCategory) {
60 			lastCategory = cgi->UI_AddOption(&messageSetting, id, va("_%s", entry->notifyType), id);
61 		} else {
62 			if (!lastCategory)
63 				Sys_Error("MSO_InitList: The first entry must be a category");
64 			cgi->UI_AddOption(&lastCategory->firstChild, id, va("_%s", entry->notifyType), id);
65 		}
66 	}
67 	cgi->UI_RegisterOption(TEXT_MESSAGEOPTIONS, messageSetting);
68 	MSO_SetMenuState(MSO_MSTATE_PREPARED, false, true);
69 }
70 
71 /**
72  * @brief Executes confuncs to update visible message options lines.
73  * @sa MSO_Init_f
74  * @todo move this into scripts
75  */
MSO_UpdateVisibleButtons(void)76 static void MSO_UpdateVisibleButtons (void)
77 {
78 	int visible;/* current line */
79 	uiOptionIterator_t iterator;
80 	uiNode_t* messageSetting = cgi->UI_GetOption(TEXT_MESSAGEOPTIONS);
81 
82 	UI_InitOptionIteratorAtIndex(messageList_scroll, messageSetting, &iterator);
83 
84 	/* update visible button lines based on current displayed values */
85 	for (visible = 0; visible < messageList_size; visible++) {
86 		const uiNode_t* option = iterator.option;
87 		int idx;
88 		msgCategoryEntry_t* entry;
89 
90 		if (!option)
91 			break;
92 		idx = atoi(OPTIONEXTRADATACONST(option).value);
93 
94 		entry = &ccs.msgCategoryEntries[idx];
95 		if (!entry)
96 			break;
97 		if (entry->isCategory) {
98 			/* category is visible anyway*/
99 			cgi->UI_ExecuteConfunc("ms_disable %i", visible);
100 
101 		} else {
102 			assert(entry->category);
103 			cgi->UI_ExecuteConfunc("ms_enable %i", visible);
104 			cgi->UI_ExecuteConfunc("ms_btnstate %i %i %i %i", visible, entry->settings->doPause,
105 				entry->settings->doNotify, entry->settings->doSound);
106 		}
107 
108 		UI_OptionIteratorNextOption(&iterator);
109 	}
110 
111 	for (; visible < messageList_size; visible++)
112 		cgi->UI_ExecuteConfunc("ms_disable %i", visible);
113 }
114 
115 /**
116  * @brief initializes message options menu by showing as much button lines as needed.
117  * @note This must only be done once as long as settings are changed in menu, so
118  * messageOptionsInitialized is checked whether this is done yet. This function will be
119  * reenabled if settings are changed via MSO_Set_f. If text list is not initialized
120  * after parsing, MSO_InitTextList will be called first.
121  */
MSOCB_Init(void)122 static void MSOCB_Init (void)
123 {
124 	if (msoMenuState < MSO_MSTATE_PREPARED) {
125 		MSO_InitList();
126 		msoMenuState = MSO_MSTATE_PREPARED;
127 	}
128 
129 	if (msoMenuState < MSO_MSTATE_INITIALIZED) {
130 		MSO_UpdateVisibleButtons();
131 		msoMenuState = MSO_MSTATE_INITIALIZED;
132 	}
133 }
134 
135 /**
136  * @brief initializes message options menu by showing as much button lines as needed.
137  * @note First facultative param (from cgi->Cmd_Arg) init messageList_size (the number of rows of button)
138  */
MSO_Init_f(void)139 static void MSO_Init_f (void)
140 {
141 	if (cgi->Cmd_Argc() == 2) {
142 		messageList_size = atoi(cgi->Cmd_Argv(1));
143 	}
144 
145 	MSOCB_Init();
146 }
147 
148 /**
149  * @brief Function for menu buttons to update message settings.
150  * @sa MSO_Set
151  * @todo move this into scripts
152  */
MSO_Toggle_f(void)153 static void MSO_Toggle_f (void)
154 {
155 	if (cgi->Cmd_Argc() != 3)
156 		Com_Printf("Usage: %s <listId> <pause|notify|sound>\n", cgi->Cmd_Argv(0));
157 	else {
158 		uiOptionIterator_t iterator;
159 		const int listIndex = atoi(cgi->Cmd_Argv(1));
160 		int idx;
161 		const msgCategoryEntry_t* selectedEntry;
162 		int optionType;
163 		bool activate;
164 		int type;
165 		uiNode_t* messageSetting = cgi->UI_GetOption(TEXT_MESSAGEOPTIONS);
166 
167 		UI_InitOptionIteratorAtIndex(messageList_scroll + listIndex, messageSetting, &iterator);
168 		if (!iterator.option)
169 			return;
170 
171 		idx = atoi(OPTIONEXTRADATA(iterator.option).value);
172 		selectedEntry = &ccs.msgCategoryEntries[idx];
173 		if (!selectedEntry)
174 			return;
175 		if (selectedEntry->isCategory) {
176 			Com_Printf("Toggle command with selected category entry ignored.\n");
177 			return;
178 		}
179 		for (type = 0; type < NT_NUM_NOTIFYTYPE; type++) {
180 			if (Q_streq(nt_strings[type], selectedEntry->notifyType))
181 				break;
182 		}
183 		if (type == NT_NUM_NOTIFYTYPE) {
184 			Com_Printf("Unrecognized messagetype during toggle '%s' ignored\n", selectedEntry->notifyType);
185 			return;
186 		}
187 
188 		if (Q_streq(cgi->Cmd_Argv(2), "pause")) {
189 			optionType = MSO_PAUSE;
190 			activate = !selectedEntry->settings->doPause;
191 		} else if (Q_streq(cgi->Cmd_Argv(2), "notify")) {
192 			optionType = MSO_NOTIFY;
193 			activate = !selectedEntry->settings->doNotify;
194 		} else {
195 			optionType = MSO_SOUND;
196 			activate = !selectedEntry->settings->doSound;
197 		}
198 		MSO_Set(listIndex, (notify_t)type, optionType, activate, true);
199 	}
200 }
201 
202 /**
203  * @brief Function to update message options menu after scrolling.
204  * Updates all visible button lines based on configuration.
205  */
MSO_Scroll_f(void)206 static void MSO_Scroll_f (void)
207 {
208 	if (cgi->Cmd_Argc() < 2)
209 		return;
210 
211 	/* no scrolling if visible entry count is less than max on page (due to folding) */
212 	messageList_scroll = atoi(cgi->Cmd_Argv(1));
213 
214 	MSO_UpdateVisibleButtons();
215 }
216 
217 /**
218  * @brief Saves actual settings into backup settings variable.
219  */
MSO_BackupSettings_f(void)220 static void MSO_BackupSettings_f (void)
221 {
222 	memcpy(backupMessageSettings, messageSettings, sizeof(backupMessageSettings));
223 }
224 
225 /**
226  * @brief Restores actual settings from backup settings variable.
227  * @note message options are caused to be re-initialized (for menu display)
228  * @sa MSO_Init_f
229  */
MSO_RestoreSettings_f(void)230 static void MSO_RestoreSettings_f (void)
231 {
232 	memcpy(messageSettings, backupMessageSettings, sizeof(messageSettings));
233 	MSO_SetMenuState(MSO_MSTATE_REINIT,false,true);
234 }
235 
MSO_SetMenuState(const msoMenuState_t newState,const bool callInit,const bool preserveIndex)236 void MSO_SetMenuState (const msoMenuState_t newState, const bool callInit, const bool preserveIndex)
237 {
238 	msoMenuState = newState;
239 	if (newState == MSO_MSTATE_REINIT && !preserveIndex) {
240 		visibleMSOEntries = 0;
241 		messageList_scroll = 0;
242 	}
243 	if (callInit)
244 		MSOCB_Init();
245 }
246 
MSO_InitCallbacks(void)247 void MSO_InitCallbacks (void)
248 {
249 	OBJSET(backupMessageSettings, 1);
250 	cgi->Cmd_AddCommand("msgoptions_toggle", MSO_Toggle_f, "Toggles pause, notification or sound setting for a message category");
251 	cgi->Cmd_AddCommand("msgoptions_scroll", MSO_Scroll_f, "Scroll callback function for message options menu text");
252 	cgi->Cmd_AddCommand("msgoptions_init", MSO_Init_f, "Initializes message options menu");
253 	cgi->Cmd_AddCommand("msgoptions_backup", MSO_BackupSettings_f, "Backup message settings");
254 	cgi->Cmd_AddCommand("msgoptions_restore",MSO_RestoreSettings_f, "Restore message settings from backup");
255 
256 }
257 
MSO_ShutdownCallbacks(void)258 void MSO_ShutdownCallbacks (void)
259 {
260 	cgi->Cmd_RemoveCommand("msgoptions_toggle");
261 	cgi->Cmd_RemoveCommand("msgoptions_scroll");
262 	cgi->Cmd_RemoveCommand("msgoptions_init");
263 	cgi->Cmd_RemoveCommand("msgoptions_backup");
264 	cgi->Cmd_RemoveCommand("msgoptions_restore");
265 	cgi->UI_ResetData(TEXT_MESSAGEOPTIONS);
266 }
267