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