]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/xonotic/keybinder.qc
07d4d6a1beea5b85a577b2173bad979e73129272
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / xonotic / keybinder.qc
1 #ifndef KEYBINDER_H
2 #define KEYBINDER_H
3 CLASS(XonoticKeyBinder, XonoticListBox)
4         METHOD(XonoticKeyBinder, configureXonoticKeyBinder, void(entity))
5         ATTRIB(XonoticKeyBinder, rowsPerItem, int, 1)
6         METHOD(XonoticKeyBinder, drawListBoxItem, void(entity, float, vector, float))
7         METHOD(XonoticKeyBinder, doubleClickListBoxItem, void(entity, float, vector))
8         METHOD(XonoticKeyBinder, resizeNotify, void(entity, vector, vector, vector, vector))
9         METHOD(XonoticKeyBinder, setSelected, void(entity, float))
10         METHOD(XonoticKeyBinder, keyDown, float(entity, float, float, float))
11         METHOD(XonoticKeyBinder, keyGrabbed, void(entity, float, float))
12
13         ATTRIB(XonoticKeyBinder, realFontSize, vector, '0 0 0')
14         ATTRIB(XonoticKeyBinder, realUpperMargin, float, 0)
15         ATTRIB(XonoticKeyBinder, columnFunctionOrigin, float, 0)
16         ATTRIB(XonoticKeyBinder, columnFunctionSize, float, 0)
17         ATTRIB(XonoticKeyBinder, columnKeysOrigin, float, 0)
18         ATTRIB(XonoticKeyBinder, columnKeysSize, float, 0)
19
20         ATTRIB(XonoticKeyBinder, previouslySelected, int, -1)
21         ATTRIB(XonoticKeyBinder, inMouseHandler, float, 0)
22         ATTRIB(XonoticKeyBinder, userbindEditButton, entity, NULL)
23         ATTRIB(XonoticKeyBinder, keyGrabButton, entity, NULL)
24         ATTRIB(XonoticKeyBinder, clearButton, entity, NULL)
25         ATTRIB(XonoticKeyBinder, userbindEditDialog, entity, NULL)
26         METHOD(XonoticKeyBinder, editUserbind, void(entity, string, string, string))
27 ENDCLASS(XonoticKeyBinder)
28 entity makeXonoticKeyBinder();
29 void KeyBinder_Bind_Change(entity btn, entity me);
30 void KeyBinder_Bind_Clear(entity btn, entity me);
31 void KeyBinder_Bind_Edit(entity btn, entity me);
32 void KeyBinder_Bind_Reset_All(entity btn, entity me);
33 #endif
34
35 #ifdef IMPLEMENTATION
36
37 const string KEY_NOT_BOUND_CMD = "// not bound";
38
39 const int MAX_KEYS_PER_FUNCTION = 2;
40 const int MAX_KEYBINDS = 256;
41 string Xonotic_KeyBinds_Functions[MAX_KEYBINDS];
42 string Xonotic_KeyBinds_Descriptions[MAX_KEYBINDS];
43 int Xonotic_KeyBinds_Count = -1;
44
45 void Xonotic_KeyBinds_Read()
46 {
47         int fh;
48         string s;
49
50         Xonotic_KeyBinds_Count = 0;
51         fh = fopen(language_filename("keybinds.txt"), FILE_READ);
52         if(fh < 0)
53                 return;
54         while((s = fgets(fh)))
55         {
56                 if(tokenize_console(s) != 2)
57                         continue;
58                 Xonotic_KeyBinds_Functions[Xonotic_KeyBinds_Count] = strzone(argv(0));
59                 Xonotic_KeyBinds_Descriptions[Xonotic_KeyBinds_Count] = strzone(argv(1));
60                 ++Xonotic_KeyBinds_Count;
61                 if(Xonotic_KeyBinds_Count >= MAX_KEYBINDS)
62                         break;
63         }
64         fclose(fh);
65 }
66
67 entity makeXonoticKeyBinder()
68 {
69         entity me;
70         me = NEW(XonoticKeyBinder);
71         me.configureXonoticKeyBinder(me);
72         return me;
73 }
74 void replace_bind(string from, string to)
75 {
76         int n, j;
77         float k; // not sure if float or int
78         n = tokenize(findkeysforcommand(from, 0)); // uses '...' strings
79         for(j = 0; j < n; ++j)
80         {
81                 k = stof(argv(j));
82                 if(k != -1)
83                         localcmd("\nbind \"", keynumtostring(k), "\" \"", to, "\"\n");
84         }
85         if(n)
86                 cvar_set("_hud_showbinds_reload", "1");
87 }
88 void XonoticKeyBinder_configureXonoticKeyBinder(entity me)
89 {
90         me.configureXonoticListBox(me);
91         if(Xonotic_KeyBinds_Count < 0)
92                 Xonotic_KeyBinds_Read();
93         me.nItems = Xonotic_KeyBinds_Count;
94         me.setSelected(me, 0);
95
96         // TEMP: Xonotic 0.1 to later
97         replace_bind("impulse 1", "weapon_group_1");
98         replace_bind("impulse 2", "weapon_group_2");
99         replace_bind("impulse 3", "weapon_group_3");
100         replace_bind("impulse 4", "weapon_group_4");
101         replace_bind("impulse 5", "weapon_group_5");
102         replace_bind("impulse 6", "weapon_group_6");
103         replace_bind("impulse 7", "weapon_group_7");
104         replace_bind("impulse 8", "weapon_group_8");
105         replace_bind("impulse 9", "weapon_group_9");
106         replace_bind("impulse 14", "weapon_group_0");
107 }
108 void XonoticKeyBinder_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
109 {
110         SUPER(XonoticKeyBinder).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
111
112         me.realFontSize_y = me.fontSize / (absSize.y * me.itemHeight);
113         me.realFontSize_x = me.fontSize / (absSize.x * (1 - me.controlWidth));
114         me.realUpperMargin = 0.5 * (1 - me.realFontSize.y);
115
116         me.columnFunctionOrigin = 0;
117         me.columnKeysSize = me.realFontSize.x * 12;
118         me.columnFunctionSize = 1 - me.columnKeysSize - 2 * me.realFontSize.x;
119         me.columnKeysOrigin = me.columnFunctionOrigin + me.columnFunctionSize + me.realFontSize.x;
120
121         if(me.userbindEditButton)
122                 me.userbindEditButton.disabled = (substring(Xonotic_KeyBinds_Descriptions[me.selectedItem], 0, 1) != "$");
123 }
124 void KeyBinder_Bind_Change(entity btn, entity me)
125 {
126         string func;
127
128         func = Xonotic_KeyBinds_Functions[me.selectedItem];
129         if(func == "")
130                 return;
131
132         me.keyGrabButton.forcePressed = 1;
133         me.clearButton.disabled = 1;
134         keyGrabber = me;
135 }
136 void XonoticKeyBinder_keyGrabbed(entity me, int key, bool ascii)
137 {
138         int n, j, nvalid;
139         float k;
140         string func;
141
142         me.keyGrabButton.forcePressed = 0;
143         me.clearButton.disabled = 0;
144
145         if(key == K_ESCAPE)
146                 return;
147
148         // forbid these keys from being bound in the menu
149         if(key == K_CAPSLOCK || key == K_NUMLOCK)
150         {
151                 KeyBinder_Bind_Change(me, me);
152                 return;
153         }
154
155         func = Xonotic_KeyBinds_Functions[me.selectedItem];
156         if(func == "")
157                 return;
158
159         n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
160         nvalid = 0;
161         for(j = 0; j < n; ++j)
162         {
163                 k = stof(argv(j));
164                 if(k != -1)
165                         ++nvalid;
166         }
167         if(nvalid >= MAX_KEYS_PER_FUNCTION)
168         {
169                 for(j = 0; j < n; ++j)
170                 {
171                         k = stof(argv(j));
172                         if(k != -1)
173                                 //localcmd("\nunbind \"", keynumtostring(k), "\"\n");
174                                 localcmd("\nbind \"", keynumtostring(k), "\" \"", KEY_NOT_BOUND_CMD, "\"\n");
175                 }
176         }
177         m_play_click_sound(MENU_SOUND_SELECT);
178         localcmd("\nbind \"", keynumtostring(key), "\" \"", func, "\"\n");
179         localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
180         cvar_set("_hud_showbinds_reload", "1");
181 }
182 void XonoticKeyBinder_editUserbind(entity me, string theName, string theCommandPress, string theCommandRelease)
183 {
184         string func, descr;
185
186         if(!me.userbindEditDialog)
187                 return;
188
189         func = Xonotic_KeyBinds_Functions[me.selectedItem];
190         if(func == "")
191                 return;
192
193         descr = Xonotic_KeyBinds_Descriptions[me.selectedItem];
194         if(substring(descr, 0, 1) != "$")
195                 return;
196         descr = substring(descr, 1, strlen(descr) - 1);
197
198         // Hooray! It IS a user bind!
199         cvar_set(strcat(descr, "_description"), theName);
200         cvar_set(strcat(descr, "_press"), theCommandPress);
201         cvar_set(strcat(descr, "_release"), theCommandRelease);
202 }
203 void KeyBinder_Bind_Edit(entity btn, entity me)
204 {
205         string func, descr;
206
207         if(!me.userbindEditDialog)
208                 return;
209
210         func = Xonotic_KeyBinds_Functions[me.selectedItem];
211         if(func == "")
212                 return;
213
214         descr = Xonotic_KeyBinds_Descriptions[me.selectedItem];
215         if(substring(descr, 0, 1) != "$")
216                 return;
217         descr = substring(descr, 1, strlen(descr) - 1);
218
219         // Hooray! It IS a user bind!
220         me.userbindEditDialog.loadUserBind(me.userbindEditDialog, cvar_string(strcat(descr, "_description")), cvar_string(strcat(descr, "_press")), cvar_string(strcat(descr, "_release")));
221
222         DialogOpenButton_Click(btn, me.userbindEditDialog);
223 }
224 void KeyBinder_Bind_Clear(entity btn, entity me)
225 {
226         float n, j, k;
227         string func;
228
229         func = Xonotic_KeyBinds_Functions[me.selectedItem];
230         if(func == "")
231                 return;
232
233         n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
234         for(j = 0; j < n; ++j)
235         {
236                 k = stof(argv(j));
237                 if(k != -1)
238                         //localcmd("\nunbind \"", keynumtostring(k), "\"\n");
239                         localcmd("\nbind \"", keynumtostring(k), "\" \"", KEY_NOT_BOUND_CMD, "\"\n");
240         }
241         m_play_click_sound(MENU_SOUND_CLEAR);
242         localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
243         cvar_set("_hud_showbinds_reload", "1");
244 }
245 void KeyBinder_Bind_Reset_All(entity btn, entity me)
246 {
247         localcmd("unbindall\n");
248         localcmd("exec binds-xonotic.cfg\n");
249         localcmd("-zoom\n"); // to make sure we aren't in togglezoom'd state
250         cvar_set("_hud_showbinds_reload", "1");
251 }
252 void XonoticKeyBinder_doubleClickListBoxItem(entity me, float i, vector where)
253 {
254         KeyBinder_Bind_Change(NULL, me);
255 }
256 void XonoticKeyBinder_setSelected(entity me, int i)
257 {
258         // handling of "unselectable" items
259         i = floor(0.5 + bound(0, i, me.nItems - 1));
260         if(me.pressed == 0 || me.pressed == 1) // keyboard or scrolling - skip unselectable items
261         {
262                 if(i > me.previouslySelected)
263                 {
264                         while((i < me.nItems - 1) && (Xonotic_KeyBinds_Functions[i] == ""))
265                                 ++i;
266                 }
267                 while((i > 0) && (Xonotic_KeyBinds_Functions[i] == ""))
268                         --i;
269                 while((i < me.nItems - 1) && (Xonotic_KeyBinds_Functions[i] == ""))
270                         ++i;
271         }
272         if(me.pressed == 3) // released the mouse - fall back to last valid item
273         {
274                 if(Xonotic_KeyBinds_Functions[i] == "")
275                         i = me.previouslySelected;
276         }
277         if(Xonotic_KeyBinds_Functions[i] != "")
278                 me.previouslySelected = i;
279         if(me.userbindEditButton)
280                 me.userbindEditButton.disabled = (substring(Xonotic_KeyBinds_Descriptions[i], 0, 1) != "$");
281         SUPER(XonoticKeyBinder).setSelected(me, i);
282 }
283 float XonoticKeyBinder_keyDown(entity me, int key, bool ascii, float shift)
284 {
285         bool r = true;
286         switch(key)
287         {
288                 case K_ENTER:
289                 case K_KP_ENTER:
290                 case K_SPACE:
291                         KeyBinder_Bind_Change(me, me);
292                         break;
293                 case K_DEL:
294                 case K_KP_DEL:
295                 case K_BACKSPACE:
296                         KeyBinder_Bind_Clear(me, me);
297                         break;
298                 default:
299                         r = SUPER(XonoticKeyBinder).keyDown(me, key, ascii, shift);
300                         break;
301         }
302         return r;
303 }
304 void XonoticKeyBinder_drawListBoxItem(entity me, int i, vector absSize, bool isSelected)
305 {
306         string s;
307         int j, n;
308         float k;
309         vector theColor;
310         float theAlpha;
311         string func, descr;
312         float extraMargin;
313
314         descr = Xonotic_KeyBinds_Descriptions[i];
315         func = Xonotic_KeyBinds_Functions[i];
316
317         if(func == "")
318         {
319                 theAlpha = 1;
320                 theColor = SKINCOLOR_KEYGRABBER_TITLES;
321                 theAlpha = SKINALPHA_KEYGRABBER_TITLES;
322                 extraMargin = 0;
323         }
324         else
325         {
326                 if(isSelected)
327                 {
328                         if(keyGrabber == me)
329                                 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_WAITING, SKINALPHA_LISTBOX_WAITING);
330                         else
331                                 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
332                 }
333                 theAlpha = SKINALPHA_KEYGRABBER_KEYS;
334                 theColor = SKINCOLOR_KEYGRABBER_KEYS;
335                 extraMargin = me.realFontSize.x * 0.5;
336         }
337
338         if(substring(descr, 0, 1) == "$")
339         {
340                 s = substring(descr, 1, strlen(descr) - 1);
341                 descr = cvar_string(strcat(s, "_description"));
342                 if(descr == "")
343                         descr = s;
344                 if(cvar_string(strcat(s, "_press")) == "")
345                         if(cvar_string(strcat(s, "_release")) == "")
346                                 theAlpha *= SKINALPHA_DISABLED;
347         }
348
349         s = draw_TextShortenToWidth(descr, me.columnFunctionSize, 0, me.realFontSize);
350         draw_Text(me.realUpperMargin * eY + extraMargin * eX, s, me.realFontSize, theColor, theAlpha, 0);
351         if(func != "")
352         {
353                 n = tokenize(findkeysforcommand(func, 0)); // uses '...' strings
354                 s = "";
355                 for(j = 0; j < n; ++j)
356                 {
357                         k = stof(argv(j));
358                         if(k != -1)
359                         {
360                                 if(s != "")
361                                         s = strcat(s, ", ");
362                                 s = strcat(s, keynumtostring(k));
363                         }
364                 }
365                 s = draw_TextShortenToWidth(s, me.columnKeysSize, 0, me.realFontSize);
366                 draw_CenterText(me.realUpperMargin * eY + (me.columnKeysOrigin + 0.5 * me.columnKeysSize) * eX, s, me.realFontSize, theColor, theAlpha, 0);
367         }
368 }
369 #endif