1 /*
2 * (c) 2004 by Kalle Wallin (kaw@linux.se)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <glib.h>
23 #include <ncurses.h>
25 #include "config.h"
27 #ifdef ENABLE_KEYDEF_SCREEN
28 #include "ncmpc.h"
29 #include "libmpdclient.h"
30 #include "options.h"
31 #include "conf.h"
32 #include "mpc.h"
33 #include "command.h"
34 #include "screen.h"
35 #include "screen_utils.h"
37 #define STATIC_ITEMS 0
38 #define STATIC_SUB_ITEMS 1
39 #define BUFSIZE 256
41 #define LIST_ITEM_APPLY() (command_list_length)
42 #define LIST_ITEM_SAVE() (LIST_ITEM_APPLY()+1)
43 #define LIST_LENGTH() (LIST_ITEM_SAVE()+1)
45 #define LIST_ITEM_SAVE_LABEL _("===> Apply & Save key bindings ")
46 #define LIST_ITEM_APPLY_LABEL _("===> Apply key bindings ")
49 static list_window_t *lw = NULL;
50 static int command_list_length = 0;
51 static command_definition_t *cmds = NULL;
53 static int subcmd = -1;
54 static int subcmd_length = 0;
55 static int subcmd_addpos = 0;
57 static int
58 keybindings_changed(void)
59 {
60 command_definition_t *orginal_cmds = get_command_definitions();
61 size_t size = command_list_length*sizeof(command_definition_t);
63 return memcmp(orginal_cmds, cmds, size);
64 }
66 static void
67 apply_keys(void)
68 {
69 if( keybindings_changed() )
70 {
71 command_definition_t *orginal_cmds = get_command_definitions();
72 size_t size = command_list_length*sizeof(command_definition_t);
74 memcpy(orginal_cmds, cmds, size);
75 screen_status_printf(_("You have new key bindings!"));
76 }
77 else
78 screen_status_printf(_("Keybindings unchanged."));
79 }
81 static int
82 save_keys(void)
83 {
84 FILE *f;
85 char *filename;
87 if( check_user_conf_dir() )
88 {
89 screen_status_printf(_("Error: Unable to create direcory ~/.ncmpc - %s"),
90 strerror(errno));
91 beep();
92 return -1;
93 }
95 filename = get_user_key_binding_filename();
97 if( (f=fopen(filename,"w")) == NULL )
98 {
99 screen_status_printf(_("Error: %s - %s"), filename, strerror(errno));
100 beep();
101 g_free(filename);
102 return -1;
103 }
104 if( write_key_bindings(f) )
105 screen_status_printf(_("Error: %s - %s"), filename, strerror(errno));
106 else
107 screen_status_printf(_("Wrote %s"), filename);
109 g_free(filename);
110 return fclose(f);
111 }
113 static void
114 check_subcmd_length(void)
115 {
116 subcmd_length = 0;
117 while( subcmd_length<MAX_COMMAND_KEYS && cmds[subcmd].keys[subcmd_length]>0 )
118 subcmd_length ++;
120 if( subcmd_length<MAX_COMMAND_KEYS )
121 {
122 subcmd_addpos = subcmd_length;
123 subcmd_length++;
124 }
125 else
126 subcmd_addpos = 0;
127 subcmd_length += STATIC_SUB_ITEMS;
128 }
130 static void
131 delete_key(int cmd_index, int key_index)
132 {
133 int i = key_index+1;
135 screen_status_printf(_("Deleted"));
136 while( i<MAX_COMMAND_KEYS && cmds[cmd_index].keys[i] )
137 cmds[cmd_index].keys[key_index++] = cmds[cmd_index].keys[i++];
138 cmds[cmd_index].keys[key_index] = 0;
140 check_subcmd_length();
141 lw->clear = 1;
142 lw->repaint = 1;
143 }
145 static void
146 assign_new_key(WINDOW *w, int cmd_index, int key_index)
147 {
148 int key;
149 char buf[BUFSIZE];
150 command_t cmd;
152 snprintf(buf, BUFSIZE, _("Enter new key for %s: "), cmds[cmd_index].name);
153 key = screen_getch(w, buf);
154 if( key==KEY_RESIZE )
155 screen_resize();
156 if( key==ERR )
157 {
158 screen_status_printf(_("Aborted!"));
159 return;
160 }
161 cmd = find_key_command(key, cmds);
162 if( cmd!=CMD_NONE && cmd!= cmds[cmd_index].command )
163 {
164 screen_status_printf(_("Error: key %s is already used for %s"),
165 key2str(key),
166 get_key_command_name(cmd));
167 beep();
168 return;
169 }
170 cmds[cmd_index].keys[key_index] = key;
171 screen_status_printf(_("Assigned %s to %s"),
172 key2str(key),cmds[cmd_index].name);
173 check_subcmd_length();
174 lw->repaint = 1;
175 }
177 static char *
178 list_callback(int index, int *highlight, void *data)
179 {
180 static char buf[BUFSIZE];
182 if( subcmd <0 )
183 {
184 if( index<command_list_length )
185 return cmds[index].name;
186 else if( index==LIST_ITEM_APPLY() )
187 return LIST_ITEM_APPLY_LABEL;
188 else if( index==LIST_ITEM_SAVE() )
189 return LIST_ITEM_SAVE_LABEL;
190 }
191 else
192 {
193 if( index== 0 )
194 return "[..]";
195 index--;
196 if( index<MAX_COMMAND_KEYS && cmds[subcmd].keys[index]>0 )
197 {
198 snprintf(buf,
199 BUFSIZE, "%d. %-20s (%d) ",
200 index+1,
201 key2str(cmds[subcmd].keys[index]),
202 cmds[subcmd].keys[index]);
203 return buf;
204 }
205 else if ( index==subcmd_addpos )
206 {
207 snprintf(buf, BUFSIZE, _("%d. Add new key "), index+1 );
208 return buf;
209 }
210 }
212 return NULL;
213 }
215 static void
216 keydef_init(WINDOW *w, int cols, int rows)
217 {
218 lw = list_window_init(w, cols, rows);
219 }
221 static void
222 keydef_resize(int cols, int rows)
223 {
224 lw->cols = cols;
225 lw->rows = rows;
226 }
228 static void
229 keydef_exit(void)
230 {
231 list_window_free(lw);
232 if( cmds )
233 g_free(cmds);
234 cmds = NULL;
235 lw = NULL;
236 }
238 static void
239 keydef_open(screen_t *screen, mpd_client_t *c)
240 {
241 if( cmds == NULL )
242 {
243 command_definition_t *current_cmds = get_command_definitions();
244 size_t cmds_size;
246 command_list_length = 0;
247 while( current_cmds[command_list_length].name )
248 command_list_length++;
250 cmds_size = (command_list_length+1)*sizeof(command_definition_t);
251 cmds = g_malloc0(cmds_size);
252 memcpy(cmds, current_cmds, cmds_size);
253 command_list_length += STATIC_ITEMS;
254 screen_status_printf(_("Welcome to the key editor!"));
255 }
257 subcmd = -1;
258 list_window_check_selected(lw, LIST_LENGTH());
259 }
261 static void
262 keydef_close(void)
263 {
264 if( cmds && !keybindings_changed() )
265 {
266 g_free(cmds);
267 cmds = NULL;
268 }
269 else
270 screen_status_printf(_("Note: Did you forget to \'Apply\' your changes?"));
271 }
273 static char *
274 keydef_title(void)
275 {
276 static char buf[BUFSIZE];
278 if( subcmd<0 )
279 return _("Edit key bindings");
281 snprintf(buf, BUFSIZE,
282 _("Edit keys for %s"),
283 cmds[subcmd].name);
284 return buf;
285 }
287 static void
288 keydef_paint(screen_t *screen, mpd_client_t *c)
289 {
290 lw->clear = 1;
291 list_window_paint(lw, list_callback, NULL);
292 wrefresh(lw->w);
293 }
295 static void
296 keydef_update(screen_t *screen, mpd_client_t *c)
297 {
298 if( lw->repaint )
299 {
300 list_window_paint(lw, list_callback, NULL);
301 wrefresh(lw->w);
302 lw->repaint = 0;
303 }
304 }
306 static int
307 keydef_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
308 {
309 int length = LIST_LENGTH();
311 if( subcmd>=0 )
312 length = subcmd_length;
314 switch(cmd)
315 {
316 case CMD_PLAY:
317 if( subcmd<0 )
318 {
319 if( lw->selected == LIST_ITEM_APPLY() )
320 apply_keys();
321 else if( lw->selected == LIST_ITEM_SAVE() )
322 {
323 apply_keys();
324 save_keys();
325 }
326 else
327 {
328 subcmd = lw->selected;
329 lw->selected=0;
330 check_subcmd_length();
331 }
332 }
333 else
334 {
335 if( lw->selected == 0 ) /* up */
336 {
337 lw->selected = subcmd;
338 subcmd = -1;
339 }
340 else
341 assign_new_key(screen->status_window.w,
342 subcmd,
343 lw->selected-STATIC_SUB_ITEMS);
344 }
345 lw->repaint = 1;
346 lw->clear = 1;
347 return 1;
348 case CMD_DELETE:
349 if( subcmd>=0 && lw->selected-STATIC_SUB_ITEMS>=0 )
350 delete_key(subcmd, lw->selected-STATIC_SUB_ITEMS);
351 return 1;
352 break;
353 case CMD_LIST_FIND:
354 case CMD_LIST_RFIND:
355 case CMD_LIST_FIND_NEXT:
356 case CMD_LIST_RFIND_NEXT:
357 return screen_find(screen, c,
358 lw, length,
359 cmd, list_callback);
361 default:
362 break;
363 }
365 return list_window_cmd(lw, length, cmd);
366 }
368 static list_window_t *
369 keydef_lw(void)
370 {
371 return lw;
372 }
374 screen_functions_t *
375 get_screen_keydef(void)
376 {
377 static screen_functions_t functions;
379 memset(&functions, 0, sizeof(screen_functions_t));
380 functions.init = keydef_init;
381 functions.exit = keydef_exit;
382 functions.open = keydef_open;
383 functions.close = keydef_close;
384 functions.resize = keydef_resize;
385 functions.paint = keydef_paint;
386 functions.update = keydef_update;
387 functions.cmd = keydef_cmd;
388 functions.get_lw = keydef_lw;
389 functions.get_title = keydef_title;
391 return &functions;
392 }
395 #endif